typescript-virtual-container 1.3.4 → 1.4.1

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 (368) hide show
  1. package/.vscode/settings.json +0 -1
  2. package/README.md +674 -1504
  3. package/benchmark-results.txt +21 -21
  4. package/builds/self-standalone.js +282 -332
  5. package/builds/self-standalone.js.map +4 -4
  6. package/builds/standalone-wo-sftp.js +218 -282
  7. package/builds/standalone-wo-sftp.js.map +4 -4
  8. package/builds/standalone.js +271 -335
  9. package/builds/standalone.js.map +4 -4
  10. package/builds/web-full-api.min.js +3 -3
  11. package/builds/web-full-api.min.js.map +4 -4
  12. package/builds/web.min.js +2 -2
  13. package/builds/web.min.js.map +4 -4
  14. package/bun.lock +14 -12
  15. package/dist/SSHClient/index.d.ts.map +1 -1
  16. package/dist/SSHClient/index.js +5 -3
  17. package/dist/SSHMimic/executor.d.ts +1 -3
  18. package/dist/SSHMimic/executor.d.ts.map +1 -1
  19. package/dist/SSHMimic/executor.js +20 -22
  20. package/dist/SSHMimic/index.d.ts.map +1 -1
  21. package/dist/SSHMimic/index.js +5 -3
  22. package/dist/SSHMimic/sftp.d.ts.map +1 -1
  23. package/dist/SSHMimic/sftp.js +26 -21
  24. package/dist/VirtualPackageManager/index.d.ts.map +1 -1
  25. package/dist/VirtualPackageManager/index.js +29 -1
  26. package/dist/VirtualShell/shell.d.ts.map +1 -1
  27. package/dist/VirtualShell/shell.js +25 -3
  28. package/dist/VirtualShell/shellParser.d.ts +1 -8
  29. package/dist/VirtualShell/shellParser.d.ts.map +1 -1
  30. package/dist/VirtualShell/shellParser.js +2 -81
  31. package/dist/VirtualUserManager/index.d.ts +7 -1
  32. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  33. package/dist/VirtualUserManager/index.js +47 -16
  34. package/dist/commands/adduser.d.ts +10 -4
  35. package/dist/commands/adduser.d.ts.map +1 -1
  36. package/dist/commands/adduser.js +75 -12
  37. package/dist/commands/alias.d.ts +5 -0
  38. package/dist/commands/alias.d.ts.map +1 -1
  39. package/dist/commands/alias.js +5 -0
  40. package/dist/commands/apt.d.ts +5 -0
  41. package/dist/commands/apt.d.ts.map +1 -1
  42. package/dist/commands/apt.js +5 -0
  43. package/dist/commands/awk.d.ts +10 -8
  44. package/dist/commands/awk.d.ts.map +1 -1
  45. package/dist/commands/awk.js +156 -28
  46. package/dist/commands/cd.d.ts.map +1 -1
  47. package/dist/commands/cd.js +0 -3
  48. package/dist/commands/clear.d.ts +5 -0
  49. package/dist/commands/clear.d.ts.map +1 -1
  50. package/dist/commands/clear.js +5 -0
  51. package/dist/commands/command-helpers.d.ts.map +1 -1
  52. package/dist/commands/command-helpers.js +8 -0
  53. package/dist/commands/curl.d.ts.map +1 -1
  54. package/dist/commands/curl.js +2 -1
  55. package/dist/commands/declare.d.ts +5 -0
  56. package/dist/commands/declare.d.ts.map +1 -1
  57. package/dist/commands/declare.js +5 -0
  58. package/dist/commands/deluser.d.ts +12 -0
  59. package/dist/commands/deluser.d.ts.map +1 -1
  60. package/dist/commands/deluser.js +72 -6
  61. package/dist/commands/df.d.ts +5 -0
  62. package/dist/commands/df.d.ts.map +1 -1
  63. package/dist/commands/df.js +5 -0
  64. package/dist/commands/du.d.ts +5 -0
  65. package/dist/commands/du.d.ts.map +1 -1
  66. package/dist/commands/du.js +5 -0
  67. package/dist/commands/export.d.ts +5 -0
  68. package/dist/commands/export.d.ts.map +1 -1
  69. package/dist/commands/export.js +5 -0
  70. package/dist/commands/grep.d.ts.map +1 -1
  71. package/dist/commands/grep.js +22 -4
  72. package/dist/commands/groups.d.ts +5 -0
  73. package/dist/commands/groups.d.ts.map +1 -1
  74. package/dist/commands/groups.js +5 -0
  75. package/dist/commands/gzip.d.ts +5 -2
  76. package/dist/commands/gzip.d.ts.map +1 -1
  77. package/dist/commands/gzip.js +54 -28
  78. package/dist/commands/head.d.ts.map +1 -1
  79. package/dist/commands/head.js +12 -3
  80. package/dist/commands/htop.d.ts +5 -0
  81. package/dist/commands/htop.d.ts.map +1 -1
  82. package/dist/commands/htop.js +5 -0
  83. package/dist/commands/kill.d.ts +5 -0
  84. package/dist/commands/kill.d.ts.map +1 -1
  85. package/dist/commands/kill.js +5 -0
  86. package/dist/commands/ln.d.ts +2 -0
  87. package/dist/commands/ln.d.ts.map +1 -1
  88. package/dist/commands/ln.js +22 -0
  89. package/dist/commands/ls.d.ts.map +1 -1
  90. package/dist/commands/ls.js +15 -0
  91. package/dist/commands/lsb-release.d.ts +5 -0
  92. package/dist/commands/lsb-release.d.ts.map +1 -1
  93. package/dist/commands/lsb-release.js +5 -0
  94. package/dist/commands/man.d.ts.map +1 -1
  95. package/dist/commands/man.js +30 -136
  96. package/dist/commands/mkdir.d.ts +5 -0
  97. package/dist/commands/mkdir.d.ts.map +1 -1
  98. package/dist/commands/mkdir.js +5 -0
  99. package/dist/commands/mv.d.ts +5 -0
  100. package/dist/commands/mv.d.ts.map +1 -1
  101. package/dist/commands/mv.js +5 -0
  102. package/dist/commands/nano.d.ts +5 -0
  103. package/dist/commands/nano.d.ts.map +1 -1
  104. package/dist/commands/nano.js +5 -0
  105. package/dist/commands/neofetch.d.ts +5 -0
  106. package/dist/commands/neofetch.d.ts.map +1 -1
  107. package/dist/commands/neofetch.js +14 -5
  108. package/dist/commands/passwd.d.ts +8 -0
  109. package/dist/commands/passwd.d.ts.map +1 -1
  110. package/dist/commands/passwd.js +32 -11
  111. package/dist/commands/ping.d.ts +5 -0
  112. package/dist/commands/ping.d.ts.map +1 -1
  113. package/dist/commands/ping.js +5 -0
  114. package/dist/commands/printf.d.ts +5 -0
  115. package/dist/commands/printf.d.ts.map +1 -1
  116. package/dist/commands/printf.js +43 -12
  117. package/dist/commands/ps.d.ts +5 -0
  118. package/dist/commands/ps.d.ts.map +1 -1
  119. package/dist/commands/ps.js +5 -0
  120. package/dist/commands/read.d.ts +5 -0
  121. package/dist/commands/read.d.ts.map +1 -1
  122. package/dist/commands/read.js +5 -0
  123. package/dist/commands/registry.d.ts.map +1 -1
  124. package/dist/commands/registry.js +4 -1
  125. package/dist/commands/rm.d.ts +5 -0
  126. package/dist/commands/rm.d.ts.map +1 -1
  127. package/dist/commands/rm.js +5 -0
  128. package/dist/commands/runtime.d.ts.map +1 -1
  129. package/dist/commands/runtime.js +1 -57
  130. package/dist/commands/sed.d.ts +5 -0
  131. package/dist/commands/sed.d.ts.map +1 -1
  132. package/dist/commands/sed.js +5 -0
  133. package/dist/commands/set.d.ts +5 -6
  134. package/dist/commands/set.d.ts.map +1 -1
  135. package/dist/commands/set.js +5 -22
  136. package/dist/commands/sh.d.ts +6 -0
  137. package/dist/commands/sh.d.ts.map +1 -1
  138. package/dist/commands/sh.js +6 -0
  139. package/dist/commands/shift.d.ts +10 -0
  140. package/dist/commands/shift.d.ts.map +1 -1
  141. package/dist/commands/shift.js +10 -0
  142. package/dist/commands/sleep.d.ts +5 -0
  143. package/dist/commands/sleep.d.ts.map +1 -1
  144. package/dist/commands/sleep.js +5 -0
  145. package/dist/commands/sort.d.ts +5 -0
  146. package/dist/commands/sort.d.ts.map +1 -1
  147. package/dist/commands/sort.js +5 -0
  148. package/dist/commands/source.d.ts +5 -0
  149. package/dist/commands/source.d.ts.map +1 -1
  150. package/dist/commands/source.js +5 -0
  151. package/dist/commands/stat.d.ts +7 -0
  152. package/dist/commands/stat.d.ts.map +1 -0
  153. package/dist/commands/stat.js +56 -0
  154. package/dist/commands/su.d.ts +13 -0
  155. package/dist/commands/su.d.ts.map +1 -1
  156. package/dist/commands/su.js +45 -14
  157. package/dist/commands/sudo.d.ts.map +1 -1
  158. package/dist/commands/sudo.js +5 -0
  159. package/dist/commands/tail.d.ts +5 -0
  160. package/dist/commands/tail.d.ts.map +1 -1
  161. package/dist/commands/tail.js +15 -3
  162. package/dist/commands/tar.d.ts +5 -0
  163. package/dist/commands/tar.d.ts.map +1 -1
  164. package/dist/commands/tar.js +40 -10
  165. package/dist/commands/tee.d.ts +5 -0
  166. package/dist/commands/tee.d.ts.map +1 -1
  167. package/dist/commands/tee.js +5 -0
  168. package/dist/commands/touch.d.ts +5 -0
  169. package/dist/commands/touch.d.ts.map +1 -1
  170. package/dist/commands/touch.js +5 -0
  171. package/dist/commands/tr.d.ts.map +1 -1
  172. package/dist/commands/tr.js +45 -10
  173. package/dist/commands/tree.d.ts +5 -0
  174. package/dist/commands/tree.d.ts.map +1 -1
  175. package/dist/commands/tree.js +5 -0
  176. package/dist/commands/true.d.ts +10 -0
  177. package/dist/commands/true.d.ts.map +1 -1
  178. package/dist/commands/true.js +10 -0
  179. package/dist/commands/type.d.ts +5 -0
  180. package/dist/commands/type.d.ts.map +1 -1
  181. package/dist/commands/type.js +5 -0
  182. package/dist/commands/uname.d.ts +5 -0
  183. package/dist/commands/uname.d.ts.map +1 -1
  184. package/dist/commands/uname.js +5 -0
  185. package/dist/commands/uniq.d.ts +5 -0
  186. package/dist/commands/uniq.d.ts.map +1 -1
  187. package/dist/commands/uniq.js +5 -0
  188. package/dist/commands/unset.d.ts +5 -0
  189. package/dist/commands/unset.d.ts.map +1 -1
  190. package/dist/commands/unset.js +5 -0
  191. package/dist/commands/uptime.d.ts +5 -0
  192. package/dist/commands/uptime.d.ts.map +1 -1
  193. package/dist/commands/uptime.js +5 -0
  194. package/dist/commands/wc.d.ts +5 -0
  195. package/dist/commands/wc.d.ts.map +1 -1
  196. package/dist/commands/wc.js +5 -0
  197. package/dist/commands/wget.d.ts +5 -0
  198. package/dist/commands/wget.d.ts.map +1 -1
  199. package/dist/commands/wget.js +16 -1
  200. package/dist/commands/who.d.ts +5 -0
  201. package/dist/commands/who.d.ts.map +1 -1
  202. package/dist/commands/who.js +5 -0
  203. package/dist/commands/whoami.d.ts +5 -0
  204. package/dist/commands/whoami.d.ts.map +1 -1
  205. package/dist/commands/whoami.js +5 -0
  206. package/dist/commands/xargs.d.ts +5 -0
  207. package/dist/commands/xargs.d.ts.map +1 -1
  208. package/dist/commands/xargs.js +5 -0
  209. package/dist/self-standalone.js +254 -30
  210. package/dist/types/commands.d.ts +36 -0
  211. package/dist/types/commands.d.ts.map +1 -1
  212. package/dist/utils/tokenize.d.ts +20 -0
  213. package/dist/utils/tokenize.d.ts.map +1 -0
  214. package/dist/utils/tokenize.js +74 -0
  215. package/examples/web.min.js +2 -2
  216. package/package.json +2 -2
  217. package/src/SSHClient/index.ts +6 -3
  218. package/src/SSHMimic/executor.ts +21 -44
  219. package/src/SSHMimic/index.ts +7 -5
  220. package/src/SSHMimic/sftp.ts +28 -21
  221. package/src/VirtualPackageManager/index.ts +29 -1
  222. package/src/VirtualShell/shell.ts +34 -4
  223. package/src/VirtualShell/shellParser.ts +2 -103
  224. package/src/VirtualUserManager/index.ts +43 -19
  225. package/src/commands/adduser.ts +86 -13
  226. package/src/commands/alias.ts +5 -0
  227. package/src/commands/apt.ts +5 -0
  228. package/src/commands/awk.ts +154 -29
  229. package/src/commands/cd.ts +0 -4
  230. package/src/commands/clear.ts +5 -0
  231. package/src/commands/command-helpers.ts +9 -0
  232. package/src/commands/curl.ts +2 -1
  233. package/src/commands/declare.ts +5 -0
  234. package/src/commands/deluser.ts +84 -7
  235. package/src/commands/df.ts +5 -0
  236. package/src/commands/du.ts +5 -0
  237. package/src/commands/export.ts +5 -0
  238. package/src/commands/grep.ts +21 -8
  239. package/src/commands/groups.ts +5 -0
  240. package/src/commands/gzip.ts +61 -28
  241. package/src/commands/head.ts +14 -4
  242. package/src/commands/htop.ts +5 -0
  243. package/src/commands/kill.ts +5 -0
  244. package/src/commands/ln.ts +22 -0
  245. package/src/commands/ls.ts +17 -0
  246. package/src/commands/lsb-release.ts +5 -0
  247. package/src/commands/man.ts +38 -143
  248. package/src/commands/manuals/adduser.txt +11 -0
  249. package/src/commands/manuals/apt-cache.txt +12 -0
  250. package/src/commands/manuals/apt.txt +20 -0
  251. package/src/commands/manuals/awk.txt +13 -0
  252. package/src/commands/manuals/cat.txt +14 -0
  253. package/src/commands/manuals/cd.txt +16 -0
  254. package/src/commands/manuals/chmod.txt +16 -0
  255. package/src/commands/manuals/clear.txt +10 -0
  256. package/src/commands/manuals/cp.txt +10 -0
  257. package/src/commands/manuals/curl.txt +20 -0
  258. package/src/commands/manuals/date.txt +14 -0
  259. package/src/commands/manuals/declare.txt +12 -0
  260. package/src/commands/manuals/deluser.txt +10 -0
  261. package/src/commands/manuals/df.txt +10 -0
  262. package/src/commands/manuals/dpkg-query.txt +11 -0
  263. package/src/commands/manuals/dpkg.txt +14 -0
  264. package/src/commands/manuals/du.txt +11 -0
  265. package/src/commands/manuals/echo.txt +11 -0
  266. package/src/commands/manuals/false.txt +10 -0
  267. package/src/commands/manuals/find.txt +11 -0
  268. package/src/commands/manuals/free.txt +12 -0
  269. package/src/commands/manuals/grep.txt +13 -0
  270. package/src/commands/manuals/groups.txt +10 -0
  271. package/src/commands/manuals/gzip.txt +11 -0
  272. package/src/commands/manuals/head.txt +10 -0
  273. package/src/commands/manuals/help.txt +11 -0
  274. package/src/commands/manuals/history.txt +11 -0
  275. package/src/commands/manuals/hostname.txt +10 -0
  276. package/src/commands/manuals/id.txt +10 -0
  277. package/src/commands/manuals/kill.txt +13 -0
  278. package/src/commands/manuals/ls.txt +20 -0
  279. package/src/commands/manuals/lsb_release.txt +14 -0
  280. package/src/commands/manuals/mkdir.txt +10 -0
  281. package/src/commands/manuals/mv.txt +10 -0
  282. package/src/commands/manuals/nano.txt +11 -0
  283. package/src/commands/manuals/neofetch.txt +10 -0
  284. package/src/commands/manuals/node.txt +13 -0
  285. package/src/commands/manuals/npm.txt +13 -0
  286. package/src/commands/manuals/npx.txt +13 -0
  287. package/src/commands/manuals/passwd.txt +11 -0
  288. package/src/commands/manuals/ping.txt +10 -0
  289. package/src/commands/manuals/printf.txt +11 -0
  290. package/src/commands/manuals/ps.txt +10 -0
  291. package/src/commands/manuals/pwd.txt +10 -0
  292. package/src/commands/manuals/python3.txt +13 -0
  293. package/src/commands/manuals/readlink.txt +10 -0
  294. package/src/commands/manuals/return.txt +10 -0
  295. package/src/commands/manuals/rm.txt +10 -0
  296. package/src/commands/manuals/sed.txt +11 -0
  297. package/src/commands/manuals/set.txt +11 -0
  298. package/src/commands/manuals/shift.txt +10 -0
  299. package/src/commands/manuals/sleep.txt +10 -0
  300. package/src/commands/manuals/sort.txt +12 -0
  301. package/src/commands/manuals/source.txt +11 -0
  302. package/src/commands/manuals/ssh.txt +11 -0
  303. package/src/commands/manuals/stat.txt +10 -0
  304. package/src/commands/manuals/su.txt +13 -0
  305. package/src/commands/manuals/sudo.txt +11 -0
  306. package/src/commands/manuals/tail.txt +10 -0
  307. package/src/commands/manuals/tar.txt +19 -0
  308. package/src/commands/manuals/tee.txt +10 -0
  309. package/src/commands/manuals/test.txt +11 -0
  310. package/src/commands/manuals/touch.txt +11 -0
  311. package/src/commands/manuals/tr.txt +10 -0
  312. package/src/commands/manuals/trap.txt +10 -0
  313. package/src/commands/manuals/true.txt +10 -0
  314. package/src/commands/manuals/type.txt +10 -0
  315. package/src/commands/manuals/uname.txt +12 -0
  316. package/src/commands/manuals/uniq.txt +12 -0
  317. package/src/commands/manuals/unset.txt +10 -0
  318. package/src/commands/manuals/uptime.txt +11 -0
  319. package/src/commands/manuals/wc.txt +12 -0
  320. package/src/commands/manuals/wget.txt +12 -0
  321. package/src/commands/manuals/which.txt +10 -0
  322. package/src/commands/manuals/whoami.txt +10 -0
  323. package/src/commands/manuals/xargs.txt +10 -0
  324. package/src/commands/mkdir.ts +5 -0
  325. package/src/commands/mv.ts +5 -0
  326. package/src/commands/nano.ts +5 -0
  327. package/src/commands/neofetch.ts +15 -6
  328. package/src/commands/passwd.ts +35 -12
  329. package/src/commands/ping.ts +5 -0
  330. package/src/commands/printf.ts +30 -13
  331. package/src/commands/ps.ts +5 -0
  332. package/src/commands/read.ts +5 -0
  333. package/src/commands/registry.ts +4 -1
  334. package/src/commands/rm.ts +5 -0
  335. package/src/commands/runtime.ts +1 -61
  336. package/src/commands/sed.ts +5 -0
  337. package/src/commands/set.ts +5 -24
  338. package/src/commands/sh.ts +9 -3
  339. package/src/commands/shift.ts +10 -0
  340. package/src/commands/sleep.ts +5 -0
  341. package/src/commands/sort.ts +5 -0
  342. package/src/commands/source.ts +5 -0
  343. package/src/commands/stat.ts +61 -0
  344. package/src/commands/su.ts +54 -16
  345. package/src/commands/sudo.ts +5 -0
  346. package/src/commands/tail.ts +17 -3
  347. package/src/commands/tar.ts +38 -15
  348. package/src/commands/tee.ts +5 -0
  349. package/src/commands/touch.ts +5 -0
  350. package/src/commands/tr.ts +54 -10
  351. package/src/commands/tree.ts +5 -0
  352. package/src/commands/true.ts +10 -0
  353. package/src/commands/type.ts +5 -0
  354. package/src/commands/uname.ts +5 -0
  355. package/src/commands/uniq.ts +5 -0
  356. package/src/commands/unset.ts +5 -0
  357. package/src/commands/uptime.ts +5 -0
  358. package/src/commands/wc.ts +5 -0
  359. package/src/commands/wget.ts +17 -1
  360. package/src/commands/who.ts +5 -0
  361. package/src/commands/whoami.ts +5 -0
  362. package/src/commands/xargs.ts +5 -0
  363. package/src/self-standalone.ts +316 -33
  364. package/src/types/commands.ts +37 -0
  365. package/src/utils/tokenize.ts +78 -0
  366. package/tests/new-features.test.ts +2 -2
  367. package/builds/web-iife.min.js +0 -13
  368. package/builds/web-iife.min.js.map +0 -7
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Shift positional parameters (remove first N arguments).
3
+ * @category shell
4
+ * @params ["[n]"]
5
+ */
1
6
  export const shiftCommand = {
2
7
  name: "shift",
3
8
  description: "Shift positional parameters",
@@ -20,6 +25,11 @@ export const shiftCommand = {
20
25
  return { exitCode: 0 };
21
26
  },
22
27
  };
28
+ /**
29
+ * Trap signals and execute actions on signal receipt or shell exit.
30
+ * @category shell
31
+ * @params ["[action] [signal...]"]
32
+ */
23
33
  export const trapCommand = {
24
34
  name: "trap",
25
35
  description: "Trap signals and events",
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Delay execution for a specified number of seconds.
4
+ * @category system
5
+ * @params ["<seconds>"]
6
+ */
2
7
  export declare const sleepCommand: ShellModule;
3
8
  //# sourceMappingURL=sleep.d.ts.map
@@ -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,WAY1B,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;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,WAY1B,CAAC"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Delay execution for a specified number of seconds.
3
+ * @category system
4
+ * @params ["<seconds>"]
5
+ */
1
6
  export const sleepCommand = {
2
7
  name: "sleep",
3
8
  description: "Delay execution",
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Sort lines of text with various options (reverse, numeric, unique).
4
+ * @category text
5
+ * @params ["[-r] [-n] [-u] [-k <col>] [file...]"]
6
+ */
2
7
  export declare const sortCommand: ShellModule;
3
8
  //# sourceMappingURL=sort.d.ts.map
@@ -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,WAoCzB,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;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,WAoCzB,CAAC"}
@@ -1,5 +1,10 @@
1
1
  import { ifFlag } from "./command-helpers";
2
2
  import { assertPathAccess, resolvePath } from "./helpers";
3
+ /**
4
+ * Sort lines of text with various options (reverse, numeric, unique).
5
+ * @category text
6
+ * @params ["[-r] [-n] [-u] [-k <col>] [file...]"]
7
+ */
3
8
  export const sortCommand = {
4
9
  name: "sort",
5
10
  description: "Sort lines of text",
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Execute commands from a file in the current shell environment.
4
+ * @category shell
5
+ * @params ["<file> [args...]"]
6
+ */
2
7
  export declare const sourceCommand: ShellModule;
3
8
  //# sourceMappingURL=source.d.ts.map
@@ -1 +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"}
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;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,WA0C3B,CAAC"}
@@ -1,5 +1,10 @@
1
1
  import { resolvePath } from "./helpers";
2
2
  import { runCommand } from "./runtime";
3
+ /**
4
+ * Execute commands from a file in the current shell environment.
5
+ * @category shell
6
+ * @params ["<file> [args...]"]
7
+ */
3
8
  export const sourceCommand = {
4
9
  name: "source",
5
10
  aliases: ["."],
@@ -0,0 +1,7 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Display file or filesystem status.
4
+ * Outputs: path, size, mode, type, timestamps — similar to `stat` on Linux.
5
+ */
6
+ export declare const statCommand: ShellModule;
7
+ //# sourceMappingURL=stat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stat.d.ts","sourceRoot":"","sources":["../../src/commands/stat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,WAqDzB,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { resolvePath } from "./helpers";
2
+ /**
3
+ * Display file or filesystem status.
4
+ * Outputs: path, size, mode, type, timestamps — similar to `stat` on Linux.
5
+ */
6
+ export const statCommand = {
7
+ name: "stat",
8
+ description: "Display file status",
9
+ category: "files",
10
+ params: ["[-c <format>] <file>"],
11
+ run: ({ shell, cwd, args }) => {
12
+ const fmtIdx = args.findIndex((a) => a === "-c" || a === "--format");
13
+ const fmt = fmtIdx !== -1 ? args[fmtIdx + 1] : undefined;
14
+ const file = args.find((a) => !a.startsWith("-") && a !== fmt);
15
+ if (!file)
16
+ return { stderr: "stat: missing operand\n", exitCode: 1 };
17
+ const p = resolvePath(cwd, file);
18
+ if (!shell.vfs.exists(p)) {
19
+ return { stderr: `stat: cannot stat '${file}': No such file or directory\n`, exitCode: 1 };
20
+ }
21
+ const st = shell.vfs.stat(p);
22
+ const isDir = st.type === "directory";
23
+ const _isLink = shell.vfs.isSymlink(p);
24
+ const isSymlink = shell.vfs.isSymlink(p);
25
+ const modePerm = (mode) => {
26
+ const bits = [0o400, 0o200, 0o100, 0o040, 0o020, 0o010, 0o004, 0o002, 0o001];
27
+ const syms = ["r", "w", "x", "r", "w", "x", "r", "w", "x"];
28
+ return (isDir ? "d" : isSymlink ? "l" : "-") +
29
+ bits.map((b, i) => mode & b ? syms[i] : "-").join("");
30
+ };
31
+ const octal = (st.mode).toString(8).padStart(4, "0");
32
+ const modeStr = modePerm(st.mode);
33
+ const size = "size" in st ? st.size : 0;
34
+ const ts = (d) => d.toISOString().replace("T", " ").replace(/\.\d+Z$/, " +0000");
35
+ // -c format string support
36
+ if (fmt) {
37
+ const out = fmt
38
+ .replace("%n", file)
39
+ .replace("%s", String(size))
40
+ .replace("%a", octal.slice(1)) // access in octal (no leading 0)
41
+ .replace("%A", modeStr)
42
+ .replace("%F", isSymlink ? "symbolic link" : isDir ? "directory" : "regular file")
43
+ .replace("%y", ts(st.updatedAt))
44
+ .replace("%z", ts(st.updatedAt));
45
+ return { stdout: `${out}\n`, exitCode: 0 };
46
+ }
47
+ const out = [
48
+ ` File: ${file}${isSymlink ? ` -> ${shell.vfs.resolveSymlink(p)}` : ""}`,
49
+ ` Size: ${size}${"\t".repeat(3)}${isSymlink ? "symbolic link" : isDir ? "directory" : "regular file"}`,
50
+ `Access: (${octal}/${modeStr}) Uid: ( 0/ root) Gid: ( 0/ root)`,
51
+ `Modify: ${ts(st.updatedAt)}`,
52
+ `Change: ${ts(st.updatedAt)}`,
53
+ ].join("\n");
54
+ return { stdout: `${out}\n`, exitCode: 0 };
55
+ },
56
+ };
@@ -1,3 +1,16 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Switch to another user account.
4
+ *
5
+ * Usage:
6
+ * su [username] — switch to username (defaults to root)
7
+ * su - [username] — login shell (changes cwd to target home)
8
+ * su -c 'cmd' [user] — run command as user
9
+ *
10
+ * - Root can switch to any user without a password.
11
+ * - Non-root sudoers must enter the target user's password.
12
+ * - Non-sudoers are denied.
13
+ * - Switching to a non-existent user returns an error immediately.
14
+ */
2
15
  export declare const suCommand: ShellModule;
3
16
  //# sourceMappingURL=su.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"su.d.ts","sourceRoot":"","sources":["../../src/commands/su.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,WA8BvB,CAAC"}
1
+ {"version":3,"file":"su.d.ts","sourceRoot":"","sources":["../../src/commands/su.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,EAAE,WAuDvB,CAAC"}
@@ -1,25 +1,56 @@
1
- import { getArg } from "./command-helpers";
1
+ import { runCommand } from "./runtime";
2
+ /**
3
+ * Switch to another user account.
4
+ *
5
+ * Usage:
6
+ * su [username] — switch to username (defaults to root)
7
+ * su - [username] — login shell (changes cwd to target home)
8
+ * su -c 'cmd' [user] — run command as user
9
+ *
10
+ * - Root can switch to any user without a password.
11
+ * - Non-root sudoers must enter the target user's password.
12
+ * - Non-sudoers are denied.
13
+ * - Switching to a non-existent user returns an error immediately.
14
+ */
2
15
  export const suCommand = {
3
16
  name: "su",
4
17
  description: "Switch user",
5
18
  category: "users",
6
- params: ["- <username>"],
7
- run: ({ authUser, shell, args }) => {
8
- const users = shell.users;
9
- const targetUser = getArg(args, 0, { flags: ["-"] });
10
- if (!targetUser) {
11
- return { stderr: "su: missing username", exitCode: 1 };
19
+ params: ["[-] [-c <cmd>] [username]"],
20
+ run: async ({ authUser, shell, args, hostname, mode, cwd }) => {
21
+ const loginShellFlag = args.includes("-") || args.includes("-l") || args.includes("--login");
22
+ const cIdx = args.indexOf("-c");
23
+ const cmdLine = cIdx !== -1 ? args[cIdx + 1] : undefined;
24
+ const filteredArgs = args.filter((_, i) => i !== cIdx && i !== cIdx + 1).filter((a) => a !== "-" && a !== "-l" && a !== "--login");
25
+ const targetUser = filteredArgs.find((a) => !a.startsWith("-")) ?? "root";
26
+ // Verify target user exists
27
+ if (!shell.users.listUsers().includes(targetUser)) {
28
+ return { stderr: `su: user '${targetUser}' does not exist\n`, exitCode: 1 };
12
29
  }
13
- if (!users.isSudoer(authUser) && authUser !== "root") {
14
- return { stderr: "su: permission denied", exitCode: 1 };
30
+ // Root switches freely without any password
31
+ if (authUser === "root") {
32
+ if (cmdLine) {
33
+ return runCommand(cmdLine, targetUser, hostname, mode, loginShellFlag ? `/home/${targetUser}` : cwd, shell);
34
+ }
35
+ return {
36
+ switchUser: targetUser,
37
+ nextCwd: loginShellFlag ? `/home/${targetUser}` : undefined,
38
+ exitCode: 0,
39
+ };
15
40
  }
16
- if (!users.verifyPassword(targetUser, getArg(args, 1) ?? "") &&
17
- authUser !== "root") {
18
- return { stderr: "su: authentication failure", exitCode: 1 };
41
+ // Non-sudoers denied
42
+ if (!shell.users.isSudoer(authUser)) {
43
+ return { stderr: "su: permission denied\n", exitCode: 1 };
19
44
  }
45
+ // Sudoers must enter target user's password via challenge
20
46
  return {
21
- switchUser: targetUser,
22
- nextCwd: `/home/${targetUser}`,
47
+ sudoChallenge: {
48
+ username: targetUser,
49
+ targetUser,
50
+ commandLine: cmdLine ?? null,
51
+ loginShell: loginShellFlag,
52
+ prompt: "Password: ",
53
+ },
23
54
  exitCode: 0,
24
55
  };
25
56
  },
@@ -1 +1 @@
1
- {"version":3,"file":"sudo.d.ts","sourceRoot":"","sources":["../../src/commands/sudo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAqBrD,eAAO,MAAM,WAAW,EAAE,WAiDzB,CAAC"}
1
+ {"version":3,"file":"sudo.d.ts","sourceRoot":"","sources":["../../src/commands/sudo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA0BrD,eAAO,MAAM,WAAW,EAAE,WAiDzB,CAAC"}
@@ -1,5 +1,10 @@
1
1
  import { parseArgs } from "./command-helpers";
2
2
  import { runCommand } from "./runtime";
3
+ /**
4
+ * Execute a command as another user (superuser by default).
5
+ * @category users
6
+ * @params ["[-u user] [-c cmd] [command]"]
7
+ */
3
8
  function parseSudoArgs(args) {
4
9
  const { flags, flagsWithValues, positionals } = parseArgs(args, {
5
10
  flags: ["-i", "-S"],
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Output the last part of files or stdin.
4
+ * @category text
5
+ * @params ["[-n <lines>] [file...]"]
6
+ */
2
7
  export declare const tailCommand: ShellModule;
3
8
  //# sourceMappingURL=tail.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tail.d.ts","sourceRoot":"","sources":["../../src/commands/tail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,WAkCzB,CAAC"}
1
+ {"version":3,"file":"tail.d.ts","sourceRoot":"","sources":["../../src/commands/tail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,WA2CzB,CAAC"}
@@ -1,5 +1,10 @@
1
1
  import { getFlag } from "./command-helpers";
2
2
  import { assertPathAccess, resolvePath } from "./helpers";
3
+ /**
4
+ * Output the last part of files or stdin.
5
+ * @category text
6
+ * @params ["[-n <lines>] [file...]"]
7
+ */
3
8
  export const tailCommand = {
4
9
  name: "tail",
5
10
  description: "Output last lines",
@@ -7,11 +12,18 @@ export const tailCommand = {
7
12
  params: ["[-n <lines>] [file...]"],
8
13
  run: ({ authUser, shell, cwd, args, stdin }) => {
9
14
  const nArg = getFlag(args, ["-n"]);
10
- const n = typeof nArg === "string" ? parseInt(nArg, 10) : 10;
11
- const positionals = args.filter((a) => !a.startsWith("-") && a !== nArg);
15
+ const shortN = args.find((a) => /^-\d+$/.test(a));
16
+ const n = typeof nArg === "string"
17
+ ? parseInt(nArg, 10)
18
+ : shortN ? parseInt(shortN.slice(1), 10) : 10;
19
+ const positionals = args.filter((a) => !a.startsWith("-") && a !== nArg && a !== String(n));
12
20
  const take = (content) => {
13
21
  const lines = content.split("\n");
14
- return lines.slice(Math.max(0, lines.length - n)).join("\n");
22
+ // If content ends with \n, last element is ""; exclude from count
23
+ const hasTrailingNewline = content.endsWith("\n");
24
+ const meaningful = hasTrailingNewline ? lines.slice(0, -1) : lines;
25
+ const sliced = meaningful.slice(Math.max(0, meaningful.length - n));
26
+ return sliced.join("\n") + (hasTrailingNewline ? "\n" : "");
15
27
  };
16
28
  if (positionals.length === 0) {
17
29
  return { stdout: take(stdin ?? ""), exitCode: 0 };
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Archive or extract files with tar and optional gzip compression.
4
+ * @category archive
5
+ * @params ["[-czf|-xzf|-tf] <archive> [files...]"]
6
+ */
2
7
  export declare const tarCommand: ShellModule;
3
8
  //# sourceMappingURL=tar.d.ts.map
@@ -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,WA0ExB,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;AAGrD;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,WA6FxB,CAAC"}
@@ -1,23 +1,53 @@
1
- import { ifFlag } from "./command-helpers";
2
1
  import { resolvePath } from "./helpers";
2
+ /**
3
+ * Archive or extract files with tar and optional gzip compression.
4
+ * @category archive
5
+ * @params ["[-czf|-xzf|-tf] <archive> [files...]"]
6
+ */
3
7
  export const tarCommand = {
4
8
  name: "tar",
5
9
  description: "Archive utility",
6
10
  category: "archive",
7
11
  params: ["[-czf|-xzf|-tf] <archive> [files...]"],
8
12
  run: ({ authUser, shell, cwd, args }) => {
9
- const create = ifFlag(args, ["-c"]);
10
- const extract = ifFlag(args, ["-x"]);
11
- const list = ifFlag(args, ["-t"]);
12
- const fFlag = args.findIndex((a) => a.includes("f"));
13
- const archiveName = fFlag !== -1
14
- ? args[fFlag + 1]
15
- : args.find((a) => a.endsWith(".tar") || a.endsWith(".tar.gz") || a.endsWith(".tgz"));
13
+ // Expand combined flags: -czf or czf (bare mode string) → ["-c", "-z", "-f"]
14
+ const expanded = [];
15
+ let foundModeStr = false;
16
+ for (const a of args) {
17
+ if (/^-[a-zA-Z]{2,}$/.test(a)) {
18
+ // -czf style
19
+ for (const ch of a.slice(1))
20
+ expanded.push(`-${ch}`);
21
+ }
22
+ else if (!foundModeStr && /^[cxtdru]{1,}[a-zA-Z]*$/.test(a) && !a.includes("/") && !a.startsWith("-")) {
23
+ // czf bare style (first non-path arg)
24
+ foundModeStr = true;
25
+ for (const ch of a)
26
+ expanded.push(`-${ch}`);
27
+ }
28
+ else {
29
+ expanded.push(a);
30
+ }
31
+ }
32
+ const create = expanded.includes("-c");
33
+ const extract = expanded.includes("-x");
34
+ const list = expanded.includes("-t");
35
+ const fIdx = expanded.indexOf("-f");
36
+ const archiveName = fIdx !== -1
37
+ ? expanded[fIdx + 1]
38
+ : expanded.find((a) => a.endsWith(".tar") || a.endsWith(".tar.gz") || a.endsWith(".tgz"));
39
+ if (!create && !extract && !list) {
40
+ return { stderr: "tar: must specify -c, -x, or -t\n", exitCode: 1 };
41
+ }
16
42
  if (!archiveName)
17
- return { stderr: "tar: no archive specified", exitCode: 1 };
43
+ return { stderr: "tar: no archive specified\n", exitCode: 1 };
18
44
  const archivePath = resolvePath(cwd, archiveName);
19
45
  if (create) {
20
- const fileArgs = args.filter((a) => !a.startsWith("-") && a !== archiveName);
46
+ // Skip flags and archive name from file list
47
+ const skipNext2 = new Set();
48
+ if (fIdx !== -1)
49
+ skipNext2.add(fIdx + 1);
50
+ const fileArgs = expanded.filter((a, i) => !a.startsWith("-") && a !== archiveName && !skipNext2.has(i));
21
51
  const entries = {};
22
52
  for (const f of fileArgs) {
23
53
  const p = resolvePath(cwd, f);
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Read stdin and write to stdout and files simultaneously.
4
+ * @category text
5
+ * @params ["[-a] <file...>"]
6
+ */
2
7
  export declare const teeCommand: ShellModule;
3
8
  //# sourceMappingURL=tee.d.ts.map
@@ -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,WA0BxB,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;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,WA0BxB,CAAC"}
@@ -1,5 +1,10 @@
1
1
  import { ifFlag } from "./command-helpers";
2
2
  import { resolvePath } from "./helpers";
3
+ /**
4
+ * Read stdin and write to stdout and files simultaneously.
5
+ * @category text
6
+ * @params ["[-a] <file...>"]
7
+ */
3
8
  export const teeCommand = {
4
9
  name: "tee",
5
10
  description: "Read stdin, write to stdout and files",
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Create empty files or update file timestamps.
4
+ * @category files
5
+ * @params ["<file>"]
6
+ */
2
7
  export declare const touchCommand: ShellModule;
3
8
  //# sourceMappingURL=touch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"touch.d.ts","sourceRoot":"","sources":["../../src/commands/touch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,YAAY,EAAE,WAmB1B,CAAC"}
1
+ {"version":3,"file":"touch.d.ts","sourceRoot":"","sources":["../../src/commands/touch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,WAmB1B,CAAC"}
@@ -1,4 +1,9 @@
1
1
  import { assertPathAccess, resolvePath } from "./helpers";
2
+ /**
3
+ * Create empty files or update file timestamps.
4
+ * @category files
5
+ * @params ["<file>"]
6
+ */
2
7
  export const touchCommand = {
3
8
  name: "touch",
4
9
  description: "Create or update files",
@@ -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,WAsBvB,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;AAgCrD,eAAO,MAAM,SAAS,EAAE,WAqCvB,CAAC"}
@@ -1,25 +1,60 @@
1
1
  import { ifFlag } from "./command-helpers";
2
+ function unescapeTrSet(s) {
3
+ return s
4
+ .replace(/\\n/g, "\n")
5
+ .replace(/\\t/g, "\t")
6
+ .replace(/\\r/g, "\r")
7
+ .replace(/\\\\/g, "\\");
8
+ }
9
+ function expandTrSet(s) {
10
+ const chars = [];
11
+ const unescaped = unescapeTrSet(s);
12
+ let i = 0;
13
+ while (i < unescaped.length) {
14
+ // Range: a-z, A-Z, 0-9
15
+ if (i + 2 < unescaped.length && unescaped[i + 1] === "-") {
16
+ const from = unescaped.charCodeAt(i);
17
+ const to = unescaped.charCodeAt(i + 2);
18
+ if (from <= to) {
19
+ for (let c = from; c <= to; c++)
20
+ chars.push(String.fromCharCode(c));
21
+ i += 3;
22
+ continue;
23
+ }
24
+ }
25
+ chars.push(unescaped[i]);
26
+ i++;
27
+ }
28
+ return chars;
29
+ }
2
30
  export const trCommand = {
3
31
  name: "tr",
4
32
  description: "Translate or delete characters",
5
33
  category: "text",
6
- params: ["[-d] <set1> [set2]"],
34
+ params: ["[-d] [-s] <set1> [set2]"],
7
35
  run: ({ args, stdin }) => {
8
36
  const del = ifFlag(args, ["-d"]);
37
+ const squeeze = ifFlag(args, ["-s"]);
9
38
  const positionals = args.filter((a) => !a.startsWith("-"));
10
- const set1 = positionals[0] ?? "";
11
- const set2 = positionals[1] ?? "";
39
+ const set1chars = expandTrSet(positionals[0] ?? "");
40
+ const set2chars = expandTrSet(positionals[1] ?? "");
12
41
  let input = stdin ?? "";
13
42
  if (del) {
14
- for (const c of set1)
15
- input = input.split(c).join("");
43
+ const deleteSet = new Set(set1chars);
44
+ input = [...input].filter((c) => !deleteSet.has(c)).join("");
16
45
  }
17
- else if (set2) {
18
- for (let i = 0; i < set1.length; i++) {
19
- input = input
20
- .split(set1[i])
21
- .join(set2[i] ?? set2[set2.length - 1] ?? "");
46
+ else if (set2chars.length > 0) {
47
+ // Build translation map
48
+ const map = new Map();
49
+ for (let i = 0; i < set1chars.length; i++) {
50
+ map.set(set1chars[i], set2chars[i] ?? set2chars[set2chars.length - 1] ?? "");
22
51
  }
52
+ input = [...input].map((c) => map.get(c) ?? c).join("");
53
+ }
54
+ if (squeeze && set2chars.length > 0) {
55
+ // Squeeze repeated characters in set2
56
+ const squeezeSet = new Set(set2chars);
57
+ input = input.replace(/(.)\1+/g, (_, c) => squeezeSet.has(c) ? c : _);
23
58
  }
24
59
  return { stdout: input, exitCode: 0 };
25
60
  },
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Display directory structure in a tree format.
4
+ * @category navigation
5
+ * @params ["[path]"]
6
+ */
2
7
  export declare const treeCommand: ShellModule;
3
8
  //# sourceMappingURL=tree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/commands/tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,WAUzB,CAAC"}
1
+ {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/commands/tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,WAUzB,CAAC"}
@@ -1,5 +1,10 @@
1
1
  import { getArg } from "./command-helpers";
2
2
  import { assertPathAccess, resolvePath } from "./helpers";
3
+ /**
4
+ * Display directory structure in a tree format.
5
+ * @category navigation
6
+ * @params ["[path]"]
7
+ */
3
8
  export const treeCommand = {
4
9
  name: "tree",
5
10
  description: "Display directory tree",
@@ -1,4 +1,14 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Always return success (exit code 0).
4
+ * @category shell
5
+ * @params []
6
+ */
2
7
  export declare const trueCommand: ShellModule;
8
+ /**
9
+ * Always return failure (exit code 1).
10
+ * @category shell
11
+ * @params []
12
+ */
3
13
  export declare const falseCommand: ShellModule;
4
14
  //# sourceMappingURL=true.d.ts.map
@@ -1 +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"}
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;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,WAMzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,WAM1B,CAAC"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Always return success (exit code 0).
3
+ * @category shell
4
+ * @params []
5
+ */
1
6
  export const trueCommand = {
2
7
  name: "true",
3
8
  description: "Return success exit code",
@@ -5,6 +10,11 @@ export const trueCommand = {
5
10
  params: [],
6
11
  run: () => ({ exitCode: 0 }),
7
12
  };
13
+ /**
14
+ * Always return failure (exit code 1).
15
+ * @category shell
16
+ * @params []
17
+ */
8
18
  export const falseCommand = {
9
19
  name: "false",
10
20
  description: "Return failure exit code",
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Describe how a command name would be interpreted (builtin, function, or file).
4
+ * @category shell
5
+ * @params ["<command...>"]
6
+ */
2
7
  export declare const typeCommand: ShellModule;
3
8
  //# sourceMappingURL=type.d.ts.map
@@ -1 +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"}
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;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,WAuCzB,CAAC"}
@@ -1,4 +1,9 @@
1
1
  import { resolveModule } from "./registry";
2
+ /**
3
+ * Describe how a command name would be interpreted (builtin, function, or file).
4
+ * @category shell
5
+ * @params ["<command...>"]
6
+ */
2
7
  export const typeCommand = {
3
8
  name: "type",
4
9
  description: "Describe how a command would be interpreted",