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,14 +1,13 @@
1
- import { getArg, ifFlag } from "./command-helpers";
1
+ import { expandAsync } from "../utils/expand";
2
+ import { ifFlag } from "./command-helpers";
2
3
  import { resolvePath } from "./helpers";
3
- import { runCommand } from "./index";
4
- /** Expand $VAR and ${VAR:-default} in a line using the current env */
5
- function expandVars(line, env, lastExit) {
6
- return line
7
- .replace(/\$\?/g, String(lastExit))
8
- .replace(/\$\{([^}:]+):-([^}]*)\}/g, (_, n, d) => env[n] ?? d)
9
- .replace(/\$\{([^}]+)\}/g, (_, n) => env[n] ?? "")
10
- .replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (_, n) => env[n] ?? "")
11
- .replace(/^~(\/|$)/, `${env.HOME ?? "/home/user"}$1`);
4
+ import { runCommand } from "./runtime";
5
+ /**
6
+ * Expand all shell forms including $(cmd) substitution.
7
+ * Delegates to centralised expandAsync (single-quote-aware, depth-tracked).
8
+ */
9
+ async function expandVars(line, env, lastExit, ctx) {
10
+ return expandAsync(line, env, lastExit, (sub) => runCommand(sub, ctx.authUser, ctx.hostname, ctx.mode, ctx.cwd, ctx.shell, undefined, ctx.env).then((r) => r.stdout ?? ""));
12
11
  }
13
12
  /** Very small shell interpreter: supports if/elif/else/fi, for/do/done, while/do/done */
14
13
  function parseBlocks(lines) {
@@ -21,7 +20,10 @@ function parseBlocks(lines) {
21
20
  continue;
22
21
  }
23
22
  if (line.startsWith("if ") || line === "if") {
24
- const cond = line.replace(/^if\s+/, "").replace(/;\s*then\s*$/, "").trim();
23
+ const cond = line
24
+ .replace(/^if\s+/, "")
25
+ .replace(/;\s*then\s*$/, "")
26
+ .trim();
25
27
  const thenLines = [];
26
28
  const elifBlocks = [];
27
29
  const elseLines = [];
@@ -32,7 +34,10 @@ function parseBlocks(lines) {
32
34
  const l = lines[i].trim();
33
35
  if (l.startsWith("elif ")) {
34
36
  section = "elif";
35
- elifCond = l.replace(/^elif\s+/, "").replace(/;\s*then\s*$/, "").trim();
37
+ elifCond = l
38
+ .replace(/^elif\s+/, "")
39
+ .replace(/;\s*then\s*$/, "")
40
+ .trim();
36
41
  elifBlocks.push({ cond: elifCond, body: [] });
37
42
  }
38
43
  else if (l === "else") {
@@ -48,8 +53,13 @@ function parseBlocks(lines) {
48
53
  }
49
54
  i++;
50
55
  }
51
- // biome-ignore lint/suspicious/noThenProperty: expected behavior for if/elif parsing
52
- blocks.push({ type: "if", cond, then: thenLines, elif: elifBlocks, else_: elseLines });
56
+ blocks.push({
57
+ type: "if",
58
+ cond,
59
+ then_: thenLines,
60
+ elif: elifBlocks,
61
+ else_: elseLines,
62
+ });
53
63
  }
54
64
  else if (line.startsWith("for ")) {
55
65
  const m = line.match(/^for\s+(\w+)\s+in\s+(.+?)(?:\s*;\s*do)?$/);
@@ -57,8 +67,8 @@ function parseBlocks(lines) {
57
67
  const body = [];
58
68
  i++;
59
69
  while (i < lines.length && lines[i]?.trim() !== "done") {
60
- const l = lines[i].trim();
61
- if (l !== "do")
70
+ const l = lines[i].trim().replace(/^do\s+/, "");
71
+ if (l && l !== "do")
62
72
  body.push(l);
63
73
  i++;
64
74
  }
@@ -69,12 +79,15 @@ function parseBlocks(lines) {
69
79
  }
70
80
  }
71
81
  else if (line.startsWith("while ")) {
72
- const cond = line.replace(/^while\s+/, "").replace(/;\s*do\s*$/, "").trim();
82
+ const cond = line
83
+ .replace(/^while\s+/, "")
84
+ .replace(/;\s*do\s*$/, "")
85
+ .trim();
73
86
  const body = [];
74
87
  i++;
75
88
  while (i < lines.length && lines[i]?.trim() !== "done") {
76
- const l = lines[i].trim();
77
- if (l !== "do")
89
+ const l = lines[i].trim().replace(/^do\s+/, "");
90
+ if (l && l !== "do")
78
91
  body.push(l);
79
92
  i++;
80
93
  }
@@ -88,7 +101,7 @@ function parseBlocks(lines) {
88
101
  return blocks;
89
102
  }
90
103
  async function evalCondition(cond, ctx) {
91
- const expanded = expandVars(cond, ctx.env.vars, ctx.env.lastExitCode);
104
+ const expanded = await expandVars(cond, ctx.env.vars, ctx.env.lastExitCode, ctx);
92
105
  // test -f / test -d / [ ... ]
93
106
  const testMatch = expanded.match(/^\[?\s*(.+?)\s*\]?$/);
94
107
  if (testMatch) {
@@ -101,7 +114,7 @@ async function evalCondition(cond, ctx) {
101
114
  if (flag === "f")
102
115
  return ctx.shell.vfs.exists(p) && ctx.shell.vfs.stat(p).type === "file";
103
116
  if (flag === "d")
104
- return ctx.shell.vfs.exists(p) && ctx.shell.vfs.stat(p).type === "directory";
117
+ return (ctx.shell.vfs.exists(p) && ctx.shell.vfs.stat(p).type === "directory");
105
118
  if (flag === "e")
106
119
  return ctx.shell.vfs.exists(p);
107
120
  if (flag === "z")
@@ -146,7 +159,21 @@ async function runBlocks(blocks, ctx) {
146
159
  let output = "";
147
160
  for (const block of blocks) {
148
161
  if (block.type === "cmd") {
149
- const expanded = expandVars(block.line, ctx.env.vars, ctx.env.lastExitCode);
162
+ const expanded = await expandVars(block.line, ctx.env.vars, ctx.env.lastExitCode, ctx);
163
+ // Bare VAR=val assignment(s) — handle before dispatching to runCommand
164
+ const assignRe = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)/;
165
+ const tokens = expanded.trim().split(/\s+/);
166
+ if (tokens.length > 0 && assignRe.test(tokens[0])) {
167
+ const allAssign = tokens.every((t) => assignRe.test(t));
168
+ if (allAssign) {
169
+ for (const tok of tokens) {
170
+ const m = tok.match(assignRe);
171
+ ctx.env.vars[m[1]] = m[2];
172
+ }
173
+ ctx.env.lastExitCode = 0;
174
+ continue;
175
+ }
176
+ }
150
177
  const r = await runCommand(expanded, ctx.authUser, ctx.hostname, ctx.mode, ctx.cwd, ctx.shell, undefined, ctx.env);
151
178
  ctx.env.lastExitCode = r.exitCode ?? 0;
152
179
  if (r.stdout)
@@ -158,7 +185,7 @@ async function runBlocks(blocks, ctx) {
158
185
  else if (block.type === "if") {
159
186
  let ran = false;
160
187
  if (await evalCondition(block.cond, ctx)) {
161
- const sub = await runBlocks(parseBlocks(block.then), ctx);
188
+ const sub = await runBlocks(parseBlocks(block.then_), ctx);
162
189
  if (sub.stdout)
163
190
  output += `${sub.stdout}\n`;
164
191
  ran = true;
@@ -181,7 +208,7 @@ async function runBlocks(blocks, ctx) {
181
208
  }
182
209
  }
183
210
  else if (block.type === "for") {
184
- const listExpanded = expandVars(block.list, ctx.env.vars, ctx.env.lastExitCode);
211
+ const listExpanded = await expandVars(block.list, ctx.env.vars, ctx.env.lastExitCode, ctx);
185
212
  const items = listExpanded.trim().split(/\s+/);
186
213
  for (const item of items) {
187
214
  ctx.env.vars[block.var] = item;
@@ -194,7 +221,7 @@ async function runBlocks(blocks, ctx) {
194
221
  }
195
222
  else if (block.type === "while") {
196
223
  let iterations = 0;
197
- while (iterations < 1000 && await evalCondition(block.cond, ctx)) {
224
+ while (iterations < 1000 && (await evalCondition(block.cond, ctx))) {
198
225
  const sub = await runBlocks(parseBlocks(block.body), ctx);
199
226
  if (sub.stdout)
200
227
  output += `${sub.stdout}\n`;
@@ -216,10 +243,13 @@ export const shCommand = {
216
243
  const { args, shell, cwd } = ctx;
217
244
  // sh -c "inline script"
218
245
  if (ifFlag(args, "-c")) {
219
- const script = getArg(args, 1) ?? "";
246
+ const script = args[args.indexOf("-c") + 1] ?? "";
220
247
  if (!script)
221
248
  return { stderr: "sh: -c requires a script", exitCode: 1 };
222
- const lines = script.split(/[;\n]/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
249
+ const lines = script
250
+ .split(/[;\n]/)
251
+ .map((l) => l.trim())
252
+ .filter((l) => l && !l.startsWith("#"));
223
253
  const blocks = parseBlocks(lines);
224
254
  return runBlocks(blocks, ctx);
225
255
  }
@@ -228,12 +258,21 @@ export const shCommand = {
228
258
  if (fileArg) {
229
259
  const p = resolvePath(cwd, fileArg);
230
260
  if (!shell.vfs.exists(p))
231
- return { stderr: `sh: ${fileArg}: No such file or directory`, exitCode: 1 };
261
+ return {
262
+ stderr: `sh: ${fileArg}: No such file or directory`,
263
+ exitCode: 1,
264
+ };
232
265
  const content = shell.vfs.readFile(p);
233
- const lines = content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
266
+ const lines = content
267
+ .split("\n")
268
+ .map((l) => l.trim())
269
+ .filter((l) => l && !l.startsWith("#"));
234
270
  const blocks = parseBlocks(lines);
235
271
  return runBlocks(blocks, ctx);
236
272
  }
237
- return { stderr: "sh: invalid usage. Use: sh -c 'cmd' or sh <file>", exitCode: 1 };
273
+ return {
274
+ stderr: "sh: invalid usage. Use: sh -c 'cmd' or sh <file>",
275
+ exitCode: 1,
276
+ };
238
277
  },
239
278
  };
@@ -0,0 +1,5 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const shiftCommand: ShellModule;
3
+ export declare const trapCommand: ShellModule;
4
+ export declare const returnCommand: ShellModule;
5
+ //# sourceMappingURL=shift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shift.d.ts","sourceRoot":"","sources":["../../src/commands/shift.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,WAoB1B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,WAezB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,WAW3B,CAAC"}
@@ -0,0 +1,52 @@
1
+ export const shiftCommand = {
2
+ name: "shift",
3
+ description: "Shift positional parameters",
4
+ category: "shell",
5
+ params: ["[n]"],
6
+ // shift is meaningful only inside sh scripts where positional params exist.
7
+ // In the current impl, positional params ($1 $2 …) aren't tracked in env by default.
8
+ // We store them under env.vars.__argv and shift there if present.
9
+ run: ({ args, env }) => {
10
+ if (!env)
11
+ return { exitCode: 0 };
12
+ const n = parseInt(args[0] ?? "1", 10) || 1;
13
+ const argv = env.vars.__argv?.split("\x00").filter(Boolean) ?? [];
14
+ env.vars.__argv = argv.slice(n).join("\x00");
15
+ // Update $1 $2 … in env
16
+ const shifted = argv.slice(n);
17
+ for (let i = 1; i <= 9; i++) {
18
+ env.vars[String(i)] = shifted[i - 1] ?? "";
19
+ }
20
+ return { exitCode: 0 };
21
+ },
22
+ };
23
+ export const trapCommand = {
24
+ name: "trap",
25
+ description: "Trap signals and events",
26
+ category: "shell",
27
+ params: ["[action] [signal...]"],
28
+ // Store trap handlers in env for EXIT signal support
29
+ run: ({ args, env }) => {
30
+ if (!env || args.length === 0)
31
+ return { exitCode: 0 };
32
+ const action = args[0] ?? "";
33
+ const signals = args.slice(1);
34
+ for (const sig of signals) {
35
+ env.vars[`__trap_${sig.toUpperCase()}`] = action;
36
+ }
37
+ return { exitCode: 0 };
38
+ },
39
+ };
40
+ export const returnCommand = {
41
+ name: "return",
42
+ description: "Return from a shell function",
43
+ category: "shell",
44
+ params: ["[n]"],
45
+ run: ({ args, env }) => {
46
+ const code = parseInt(args[0] ?? "0", 10);
47
+ if (env)
48
+ env.lastExitCode = code;
49
+ // Signal the caller via exitCode; function return is handled by runBlocks
50
+ return { exitCode: code };
51
+ },
52
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/commands/sleep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,WAW1B,CAAC"}
1
+ {"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/commands/sleep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,WAY1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../../src/commands/sort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,WAgCzB,CAAC"}
1
+ {"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../../src/commands/sort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,WAoCzB,CAAC"}
@@ -12,7 +12,8 @@ export const sortCommand = {
12
12
  const files = args.filter((a) => !a.startsWith("-"));
13
13
  const getContent = () => {
14
14
  if (files.length > 0) {
15
- return files.map((f) => {
15
+ return files
16
+ .map((f) => {
16
17
  try {
17
18
  assertPathAccess(authUser, resolvePath(cwd, f), "sort");
18
19
  return shell.vfs.readFile(resolvePath(cwd, f));
@@ -20,7 +21,8 @@ export const sortCommand = {
20
21
  catch {
21
22
  return "";
22
23
  }
23
- }).join("\n");
24
+ })
25
+ .join("\n");
24
26
  }
25
27
  return stdin ?? "";
26
28
  };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const sourceCommand: ShellModule;
3
+ //# sourceMappingURL=source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/commands/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,aAAa,EAAE,WA0C3B,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { resolvePath } from "./helpers";
2
+ import { runCommand } from "./runtime";
3
+ export const sourceCommand = {
4
+ name: "source",
5
+ aliases: ["."],
6
+ description: "Execute commands from a file in the current shell environment",
7
+ category: "shell",
8
+ params: ["<file> [args...]"],
9
+ run: async ({ args, authUser, hostname, cwd, shell, env }) => {
10
+ const fileArg = args[0];
11
+ if (!fileArg) {
12
+ return { stderr: "source: missing filename", exitCode: 1 };
13
+ }
14
+ const filePath = resolvePath(cwd, fileArg);
15
+ if (!shell.vfs.exists(filePath)) {
16
+ return {
17
+ stderr: `source: ${fileArg}: No such file or directory`,
18
+ exitCode: 1,
19
+ };
20
+ }
21
+ const content = shell.vfs.readFile(filePath);
22
+ let lastExitCode = 0;
23
+ for (const line of content.split("\n")) {
24
+ const l = line.trim();
25
+ if (!l || l.startsWith("#"))
26
+ continue;
27
+ const result = await runCommand(l, authUser, hostname, "shell", cwd, shell, undefined, env);
28
+ lastExitCode = result.exitCode ?? 0;
29
+ if (result.closeSession || result.switchUser)
30
+ return result;
31
+ }
32
+ return { exitCode: lastExitCode };
33
+ },
34
+ };
@@ -1,5 +1,5 @@
1
1
  import { parseArgs } from "./command-helpers";
2
- import { runCommand } from "./index";
2
+ import { runCommand } from "./runtime";
3
3
  function parseSudoArgs(args) {
4
4
  const { flags, flagsWithValues, positionals } = parseArgs(args, {
5
5
  flags: ["-i", "-S"],
@@ -1 +1 @@
1
- {"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../../src/commands/tar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WAqDxB,CAAC"}
1
+ {"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../../src/commands/tar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WA0ExB,CAAC"}
@@ -10,7 +10,9 @@ export const tarCommand = {
10
10
  const extract = ifFlag(args, ["-x"]);
11
11
  const list = ifFlag(args, ["-t"]);
12
12
  const fFlag = args.findIndex((a) => a.includes("f"));
13
- const archiveName = fFlag !== -1 ? args[fFlag + 1] : args.find((a) => a.endsWith(".tar") || a.endsWith(".tar.gz") || a.endsWith(".tgz"));
13
+ const archiveName = fFlag !== -1
14
+ ? args[fFlag + 1]
15
+ : args.find((a) => a.endsWith(".tar") || a.endsWith(".tar.gz") || a.endsWith(".tgz"));
14
16
  if (!archiveName)
15
17
  return { stderr: "tar: no archive specified", exitCode: 1 };
16
18
  const archivePath = resolvePath(cwd, archiveName);
@@ -38,7 +40,10 @@ export const tarCommand = {
38
40
  }
39
41
  }
40
42
  catch {
41
- return { stderr: `tar: ${f}: No such file or directory`, exitCode: 1 };
43
+ return {
44
+ stderr: `tar: ${f}: No such file or directory`,
45
+ exitCode: 1,
46
+ };
42
47
  }
43
48
  }
44
49
  shell.writeFileAsUser(authUser, archivePath, JSON.stringify(entries));
@@ -50,7 +55,10 @@ export const tarCommand = {
50
55
  entries = JSON.parse(shell.vfs.readFile(archivePath));
51
56
  }
52
57
  catch {
53
- return { stderr: `tar: ${archiveName}: cannot open archive`, exitCode: 1 };
58
+ return {
59
+ stderr: `tar: ${archiveName}: cannot open archive`,
60
+ exitCode: 1,
61
+ };
54
62
  }
55
63
  if (list)
56
64
  return { stdout: Object.keys(entries).join("\n"), exitCode: 0 };
@@ -1 +1 @@
1
- {"version":3,"file":"tee.d.ts","sourceRoot":"","sources":["../../src/commands/tee.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WAoBxB,CAAC"}
1
+ {"version":3,"file":"tee.d.ts","sourceRoot":"","sources":["../../src/commands/tee.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WA0BxB,CAAC"}
@@ -12,12 +12,14 @@ export const teeCommand = {
12
12
  for (const f of files) {
13
13
  const p = resolvePath(cwd, f);
14
14
  if (append) {
15
- const existing = (() => { try {
16
- return shell.vfs.readFile(p);
17
- }
18
- catch {
19
- return "";
20
- } })();
15
+ const existing = (() => {
16
+ try {
17
+ return shell.vfs.readFile(p);
18
+ }
19
+ catch {
20
+ return "";
21
+ }
22
+ })();
21
23
  shell.writeFileAsUser(authUser, p, existing + input);
22
24
  }
23
25
  else {
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const testCommand: ShellModule;
3
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAwHrD,eAAO,MAAM,WAAW,EAAE,WAczB,CAAC"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Evaluate a POSIX test expression.
3
+ * Supports: -f, -d, -e, -r, -w, -x, -s, -z, -n,
4
+ * string =, !=, numeric -eq -ne -lt -le -gt -ge,
5
+ * ! (negate), -a (and), -o (or).
6
+ */
7
+ function evalTest(tokens, shell, cwd) {
8
+ // When called via [ command, ] is the last arg — strip it
9
+ // When called via test command, no brackets present
10
+ if (tokens[tokens.length - 1] === "]") {
11
+ tokens = tokens.slice(0, -1);
12
+ }
13
+ // Also strip leading [ if present (shouldn't normally happen but be safe)
14
+ if (tokens[0] === "[") {
15
+ tokens = tokens.slice(1);
16
+ }
17
+ if (tokens.length === 0)
18
+ return false;
19
+ // Negation
20
+ if (tokens[0] === "!")
21
+ return !evalTest(tokens.slice(1), shell, cwd);
22
+ // Boolean -a / -o (simple left-right, no precedence)
23
+ const andIdx = tokens.indexOf("-a");
24
+ if (andIdx !== -1) {
25
+ return (evalTest(tokens.slice(0, andIdx), shell, cwd) &&
26
+ evalTest(tokens.slice(andIdx + 1), shell, cwd));
27
+ }
28
+ const orIdx = tokens.indexOf("-o");
29
+ if (orIdx !== -1) {
30
+ return (evalTest(tokens.slice(0, orIdx), shell, cwd) ||
31
+ evalTest(tokens.slice(orIdx + 1), shell, cwd));
32
+ }
33
+ // Unary file tests
34
+ if (tokens.length === 2) {
35
+ const [flag, operand = ""] = tokens;
36
+ const resolvePath = (p) => p.startsWith("/") ? p : `${cwd}/${p}`.replace(/\/+/g, "/");
37
+ const path = resolvePath(operand);
38
+ switch (flag) {
39
+ case "-e":
40
+ return shell.vfs.exists(path);
41
+ case "-f":
42
+ return shell.vfs.exists(path) && shell.vfs.stat(path).type === "file";
43
+ case "-d":
44
+ return (shell.vfs.exists(path) && shell.vfs.stat(path).type === "directory");
45
+ case "-r":
46
+ return shell.vfs.exists(path); // all readable in virtual env
47
+ case "-w":
48
+ return shell.vfs.exists(path);
49
+ case "-x":
50
+ return shell.vfs.exists(path) && !!(shell.vfs.stat(path).mode & 0o111);
51
+ case "-s":
52
+ return (shell.vfs.exists(path) &&
53
+ shell.vfs.stat(path).type === "file" &&
54
+ shell.vfs.stat(path).size > 0);
55
+ case "-z":
56
+ return operand.length === 0;
57
+ case "-n":
58
+ return operand.length > 0;
59
+ case "-L":
60
+ return shell.vfs.isSymlink(path);
61
+ }
62
+ }
63
+ // Binary comparisons
64
+ if (tokens.length === 3) {
65
+ const [left = "", op, right = ""] = tokens;
66
+ const leftN = Number(left);
67
+ const rightN = Number(right);
68
+ switch (op) {
69
+ // String
70
+ case "=":
71
+ case "==":
72
+ return left === right;
73
+ case "!=":
74
+ return left !== right;
75
+ case "<":
76
+ return left < right;
77
+ case ">":
78
+ return left > right;
79
+ // Numeric
80
+ case "-eq":
81
+ return leftN === rightN;
82
+ case "-ne":
83
+ return leftN !== rightN;
84
+ case "-lt":
85
+ return leftN < rightN;
86
+ case "-le":
87
+ return leftN <= rightN;
88
+ case "-gt":
89
+ return leftN > rightN;
90
+ case "-ge":
91
+ return leftN >= rightN;
92
+ }
93
+ }
94
+ // Single string (truthy if non-empty)
95
+ if (tokens.length === 1)
96
+ return (tokens[0] ?? "").length > 0;
97
+ return false;
98
+ }
99
+ export const testCommand = {
100
+ name: "test",
101
+ aliases: ["["],
102
+ description: "Evaluate conditional expression",
103
+ category: "shell",
104
+ params: ["<expression>"],
105
+ run: ({ args, shell, cwd }) => {
106
+ try {
107
+ const result = evalTest([...args], shell, cwd);
108
+ return { exitCode: result ? 0 : 1 };
109
+ }
110
+ catch {
111
+ return { stderr: "test: malformed expression", exitCode: 2 };
112
+ }
113
+ },
114
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"tr.d.ts","sourceRoot":"","sources":["../../src/commands/tr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,WAoBvB,CAAC"}
1
+ {"version":3,"file":"tr.d.ts","sourceRoot":"","sources":["../../src/commands/tr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,WAsBvB,CAAC"}
@@ -16,7 +16,9 @@ export const trCommand = {
16
16
  }
17
17
  else if (set2) {
18
18
  for (let i = 0; i < set1.length; i++) {
19
- input = input.split(set1[i]).join(set2[i] ?? set2[set2.length - 1] ?? "");
19
+ input = input
20
+ .split(set1[i])
21
+ .join(set2[i] ?? set2[set2.length - 1] ?? "");
20
22
  }
21
23
  }
22
24
  return { stdout: input, exitCode: 0 };
@@ -0,0 +1,4 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const trueCommand: ShellModule;
3
+ export declare const falseCommand: ShellModule;
4
+ //# sourceMappingURL=true.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"true.d.ts","sourceRoot":"","sources":["../../src/commands/true.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,WAMzB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,WAM1B,CAAC"}
@@ -0,0 +1,14 @@
1
+ export const trueCommand = {
2
+ name: "true",
3
+ description: "Return success exit code",
4
+ category: "shell",
5
+ params: [],
6
+ run: () => ({ exitCode: 0 }),
7
+ };
8
+ export const falseCommand = {
9
+ name: "false",
10
+ description: "Return failure exit code",
11
+ category: "shell",
12
+ params: [],
13
+ run: () => ({ exitCode: 1 }),
14
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const typeCommand: ShellModule;
3
+ //# sourceMappingURL=type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../src/commands/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,WAAW,EAAE,WAuCzB,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { resolveModule } from "./registry";
2
+ export const typeCommand = {
3
+ name: "type",
4
+ description: "Describe how a command would be interpreted",
5
+ category: "shell",
6
+ params: ["<command...>"],
7
+ run: ({ args, shell, env }) => {
8
+ if (args.length === 0)
9
+ return { stderr: "type: missing argument", exitCode: 1 };
10
+ const pathDirs = (env?.vars?.PATH ?? "/usr/local/bin:/usr/bin:/bin").split(":");
11
+ const lines = [];
12
+ let exitCode = 0;
13
+ for (const name of args) {
14
+ if (resolveModule(name)) {
15
+ lines.push(`${name} is a shell builtin`);
16
+ continue;
17
+ }
18
+ let found = false;
19
+ for (const dir of pathDirs) {
20
+ const full = `${dir}/${name}`;
21
+ if (shell.vfs.exists(full)) {
22
+ lines.push(`${name} is ${full}`);
23
+ found = true;
24
+ break;
25
+ }
26
+ }
27
+ if (!found) {
28
+ lines.push(`${name}: not found`);
29
+ exitCode = 1;
30
+ }
31
+ }
32
+ return { stdout: lines.join("\n"), exitCode };
33
+ },
34
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"uname.d.ts","sourceRoot":"","sources":["../../src/commands/uname.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,YAAY,EAAE,WAgB1B,CAAC"}
1
+ {"version":3,"file":"uname.d.ts","sourceRoot":"","sources":["../../src/commands/uname.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,YAAY,EAAE,WAoB1B,CAAC"}
@@ -11,7 +11,10 @@ export const unameCommand = {
11
11
  const machine = shell.properties?.arch ?? "x86_64";
12
12
  const hostname = shell.hostname;
13
13
  if (all)
14
- return { stdout: `${sysname} ${hostname} ${release} #1 SMP ${machine} GNU/Linux`, exitCode: 0 };
14
+ return {
15
+ stdout: `${sysname} ${hostname} ${release} #1 SMP ${machine} GNU/Linux`,
16
+ exitCode: 0,
17
+ };
15
18
  if (ifFlag(args, ["-r"]))
16
19
  return { stdout: release, exitCode: 0 };
17
20
  if (ifFlag(args, ["-m"]))
@@ -1 +1 @@
1
- {"version":3,"file":"uniq.d.ts","sourceRoot":"","sources":["../../src/commands/uniq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,WAAW,EAAE,WAwBzB,CAAC"}
1
+ {"version":3,"file":"uniq.d.ts","sourceRoot":"","sources":["../../src/commands/uniq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,WAAW,EAAE,WA8BzB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const uptimeCommand: ShellModule;
3
+ //# sourceMappingURL=uptime.d.ts.map