typescript-virtual-container 1.5.3 → 1.5.5

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 (371) hide show
  1. package/README.md +44 -532
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/SSHMimic/executor.js +23 -5
  4. package/dist/VirtualPackageManager/index.js +10 -0
  5. package/dist/VirtualShell/shell.js +158 -11
  6. package/dist/commands/basename.d.ts +13 -0
  7. package/dist/commands/basename.js +45 -0
  8. package/dist/commands/bc.d.ts +2 -0
  9. package/dist/commands/bc.js +28 -0
  10. package/dist/commands/file.d.ts +8 -0
  11. package/dist/commands/file.js +57 -0
  12. package/dist/commands/fun.d.ts +32 -0
  13. package/dist/commands/fun.js +172 -0
  14. package/dist/commands/ip.d.ts +7 -0
  15. package/dist/commands/ip.js +52 -0
  16. package/dist/commands/jobs.d.ts +4 -0
  17. package/dist/commands/jobs.js +27 -0
  18. package/dist/commands/last.d.ts +13 -0
  19. package/dist/commands/last.js +68 -0
  20. package/dist/commands/manuals-bundle.js +598 -6
  21. package/dist/commands/registry.js +30 -2
  22. package/dist/commands/runtime.js +24 -3
  23. package/dist/commands/set.js +20 -0
  24. package/dist/commands/sh.js +74 -1
  25. package/dist/commands/tput.d.ts +13 -0
  26. package/dist/commands/tput.js +76 -0
  27. package/dist/commands/w.d.ts +7 -0
  28. package/dist/commands/w.js +38 -0
  29. package/dist/utils/expand.d.ts +12 -0
  30. package/dist/utils/expand.js +87 -1
  31. package/package.json +9 -3
  32. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -50
  33. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -31
  34. package/.github/dependabot.yml +0 -27
  35. package/.github/pull_request_template.md +0 -21
  36. package/.github/workflows/create-pull-request.yml +0 -85
  37. package/.github/workflows/publish.yml +0 -25
  38. package/.github/workflows/test-battery.yml +0 -102
  39. package/.vscode/settings.json +0 -20
  40. package/CODE_OF_CONDUCT.md +0 -39
  41. package/CONTRIBUTING.md +0 -59
  42. package/HONEYPOT.md +0 -358
  43. package/SECURITY.md +0 -33
  44. package/benchmark-results.txt +0 -40
  45. package/benchmark-virtualshell.ts +0 -88
  46. package/biome.json +0 -37
  47. package/build.js +0 -22
  48. package/builds/fortune-nyx-v1.5.3-directbash-k6.1.0.mjs +0 -1764
  49. package/builds/fortune-nyx-v1.5.3-ssh-nosftp.js +0 -1764
  50. package/builds/fortune-nyx-v1.5.3-ssh.cjs +0 -1765
  51. package/builds/fortune-nyx-v1.5.3-web.min.js +0 -17036
  52. package/bun.lock +0 -244
  53. package/docs/.nojekyll +0 -1
  54. package/docs/app.js +0 -1751
  55. package/docs/assets/hierarchy.js +0 -1
  56. package/docs/assets/highlight.css +0 -162
  57. package/docs/assets/icons.js +0 -18
  58. package/docs/assets/icons.svg +0 -1
  59. package/docs/assets/main.js +0 -60
  60. package/docs/assets/navigation.js +0 -1
  61. package/docs/assets/search.js +0 -1
  62. package/docs/assets/style.css +0 -1633
  63. package/docs/classes/HoneyPot.html +0 -31
  64. package/docs/classes/IdleManager.html +0 -162
  65. package/docs/classes/SshClient.html +0 -66
  66. package/docs/classes/VirtualFileSystem.html +0 -279
  67. package/docs/classes/VirtualPackageManager.html +0 -63
  68. package/docs/classes/VirtualSftpServer.html +0 -169
  69. package/docs/classes/VirtualShell.html +0 -285
  70. package/docs/classes/VirtualSshServer.html +0 -182
  71. package/docs/classes/VirtualUserManager.html +0 -276
  72. package/docs/demo.html +0 -82
  73. package/docs/functions/assertDiff.html +0 -6
  74. package/docs/functions/diffSnapshots.html +0 -7
  75. package/docs/functions/formatDiff.html +0 -6
  76. package/docs/functions/getArg.html +0 -13
  77. package/docs/functions/getFlag.html +0 -15
  78. package/docs/functions/ifFlag.html +0 -11
  79. package/docs/hierarchy.html +0 -1
  80. package/docs/index.html +0 -1869
  81. package/docs/interfaces/AuditLogEntry.html +0 -6
  82. package/docs/interfaces/CommandContext.html +0 -22
  83. package/docs/interfaces/CommandResult.html +0 -26
  84. package/docs/interfaces/ExecStream.html +0 -11
  85. package/docs/interfaces/HoneyPotStats.html +0 -16
  86. package/docs/interfaces/IdleManagerOptions.html +0 -7
  87. package/docs/interfaces/InstalledPackage.html +0 -20
  88. package/docs/interfaces/NanoEditorSession.html +0 -8
  89. package/docs/interfaces/PackageDefinition.html +0 -30
  90. package/docs/interfaces/PackageFile.html +0 -8
  91. package/docs/interfaces/PasswordChallenge.html +0 -16
  92. package/docs/interfaces/RemoveOptions.html +0 -4
  93. package/docs/interfaces/ShellEnv.html +0 -6
  94. package/docs/interfaces/ShellModule.html +0 -14
  95. package/docs/interfaces/ShellProperties.html +0 -14
  96. package/docs/interfaces/ShellStream.html +0 -11
  97. package/docs/interfaces/SudoChallenge.html +0 -24
  98. package/docs/interfaces/VfsBaseNode.html +0 -12
  99. package/docs/interfaces/VfsDiff.html +0 -10
  100. package/docs/interfaces/VfsDiffEntry.html +0 -6
  101. package/docs/interfaces/VfsDiffModified.html +0 -10
  102. package/docs/interfaces/VfsDirectoryNode.html +0 -15
  103. package/docs/interfaces/VfsFileNode.html +0 -17
  104. package/docs/interfaces/VfsOptions.html +0 -26
  105. package/docs/interfaces/VfsSnapshot.html +0 -3
  106. package/docs/interfaces/VfsSnapshotBaseNode.html +0 -8
  107. package/docs/interfaces/VfsSnapshotDirectoryNode.html +0 -10
  108. package/docs/interfaces/VfsSnapshotFileNode.html +0 -12
  109. package/docs/interfaces/VirtualActiveSession.html +0 -12
  110. package/docs/interfaces/VirtualSftpServerOptions.html +0 -7
  111. package/docs/interfaces/VirtualShellVfsLike.html +0 -15
  112. package/docs/interfaces/VirtualShellVfsOptions.html +0 -3
  113. package/docs/interfaces/WriteFileOptions.html +0 -6
  114. package/docs/media/LICENSE +0 -21
  115. package/docs/modules.html +0 -1
  116. package/docs/types/ArgParseOptions.html +0 -4
  117. package/docs/types/CommandMode.html +0 -2
  118. package/docs/types/CommandOutcome.html +0 -2
  119. package/docs/types/IdleState.html +0 -1
  120. package/docs/types/VfsNodeStats.html +0 -2
  121. package/docs/types/VfsNodeType.html +0 -2
  122. package/docs/types/VfsPersistenceMode.html +0 -5
  123. package/docs/types/VfsSnapshotNode.html +0 -2
  124. package/examples/README.md +0 -288
  125. package/examples/app.js +0 -1751
  126. package/examples/app.ts +0 -299
  127. package/examples/build.js +0 -27
  128. package/examples/demo.html +0 -33
  129. package/examples/honeypot-audit.ts +0 -180
  130. package/examples/honeypot-export.ts +0 -253
  131. package/examples/honeypot-quickstart.ts +0 -110
  132. package/examples/index.html +0 -82
  133. package/examples/server.js +0 -55
  134. package/polyfills/buffer.js +0 -117
  135. package/polyfills/node_child_process/index.js +0 -2
  136. package/polyfills/node_crypto/index.js +0 -167
  137. package/polyfills/node_events/index.js +0 -9
  138. package/polyfills/node_fs/index.js +0 -202
  139. package/polyfills/node_fs/promises.js +0 -4
  140. package/polyfills/node_os/index.js +0 -9
  141. package/polyfills/node_path/index.js +0 -28
  142. package/polyfills/node_vm/index.js +0 -7
  143. package/polyfills/node_zlib/index.js +0 -3
  144. package/polyfills/process.js +0 -14
  145. package/polyfills/ssh2/index.js +0 -75
  146. package/scripts/build-all.mjs +0 -226
  147. package/scripts/build-names.mjs +0 -43
  148. package/scripts/generate-manuals-bundle.mjs +0 -49
  149. package/scripts/postinstall.js +0 -42
  150. package/scripts/publish-package.sh +0 -70
  151. package/src/Honeypot/index.ts +0 -457
  152. package/src/SSHClient/index.ts +0 -270
  153. package/src/SSHMimic/exec.ts +0 -49
  154. package/src/SSHMimic/executor.ts +0 -251
  155. package/src/SSHMimic/hostKey.ts +0 -21
  156. package/src/SSHMimic/index.ts +0 -337
  157. package/src/SSHMimic/loginBanner.ts +0 -36
  158. package/src/SSHMimic/loginFormat.ts +0 -10
  159. package/src/SSHMimic/prompt.ts +0 -14
  160. package/src/SSHMimic/sftp.ts +0 -883
  161. package/src/VirtualFileSystem/binaryPack.ts +0 -258
  162. package/src/VirtualFileSystem/index.ts +0 -1193
  163. package/src/VirtualFileSystem/internalTypes.ts +0 -43
  164. package/src/VirtualFileSystem/journal.ts +0 -171
  165. package/src/VirtualFileSystem/path.ts +0 -74
  166. package/src/VirtualPackageManager/index.ts +0 -996
  167. package/src/VirtualShell/idleManager.ts +0 -137
  168. package/src/VirtualShell/index.ts +0 -475
  169. package/src/VirtualShell/shell.ts +0 -700
  170. package/src/VirtualShell/shellParser.ts +0 -285
  171. package/src/VirtualUserManager/index.ts +0 -758
  172. package/src/bun.d.ts +0 -1
  173. package/src/commands/adduser.ts +0 -103
  174. package/src/commands/alias.ts +0 -69
  175. package/src/commands/apt.ts +0 -233
  176. package/src/commands/awk.ts +0 -168
  177. package/src/commands/base64.ts +0 -29
  178. package/src/commands/cat.ts +0 -52
  179. package/src/commands/cd.ts +0 -25
  180. package/src/commands/chmod.ts +0 -85
  181. package/src/commands/clear.ts +0 -15
  182. package/src/commands/command-helpers.ts +0 -286
  183. package/src/commands/cp.ts +0 -83
  184. package/src/commands/curl.ts +0 -147
  185. package/src/commands/cut.ts +0 -36
  186. package/src/commands/date.ts +0 -30
  187. package/src/commands/declare.ts +0 -49
  188. package/src/commands/deluser.ts +0 -98
  189. package/src/commands/df.ts +0 -23
  190. package/src/commands/diff.ts +0 -43
  191. package/src/commands/dpkg.ts +0 -180
  192. package/src/commands/du.ts +0 -56
  193. package/src/commands/echo.ts +0 -58
  194. package/src/commands/env.ts +0 -23
  195. package/src/commands/exit.ts +0 -18
  196. package/src/commands/export.ts +0 -34
  197. package/src/commands/find.ts +0 -68
  198. package/src/commands/free.ts +0 -47
  199. package/src/commands/grep.ts +0 -116
  200. package/src/commands/groups.ts +0 -19
  201. package/src/commands/gzip.ts +0 -88
  202. package/src/commands/head.ts +0 -52
  203. package/src/commands/help.ts +0 -152
  204. package/src/commands/helpers.ts +0 -234
  205. package/src/commands/history.ts +0 -34
  206. package/src/commands/hostname.ts +0 -14
  207. package/src/commands/htop.ts +0 -20
  208. package/src/commands/id.ts +0 -19
  209. package/src/commands/index.ts +0 -9
  210. package/src/commands/kill.ts +0 -19
  211. package/src/commands/ln.ts +0 -71
  212. package/src/commands/ls.ts +0 -243
  213. package/src/commands/lsb-release.ts +0 -63
  214. package/src/commands/man.ts +0 -31
  215. package/src/commands/manuals/adduser.txt +0 -11
  216. package/src/commands/manuals/apt-cache.txt +0 -12
  217. package/src/commands/manuals/apt.txt +0 -20
  218. package/src/commands/manuals/awk.txt +0 -13
  219. package/src/commands/manuals/cat.txt +0 -14
  220. package/src/commands/manuals/cd.txt +0 -16
  221. package/src/commands/manuals/chmod.txt +0 -16
  222. package/src/commands/manuals/clear.txt +0 -10
  223. package/src/commands/manuals/cp.txt +0 -10
  224. package/src/commands/manuals/curl.txt +0 -20
  225. package/src/commands/manuals/date.txt +0 -14
  226. package/src/commands/manuals/declare.txt +0 -12
  227. package/src/commands/manuals/deluser.txt +0 -10
  228. package/src/commands/manuals/df.txt +0 -10
  229. package/src/commands/manuals/dpkg-query.txt +0 -11
  230. package/src/commands/manuals/dpkg.txt +0 -14
  231. package/src/commands/manuals/du.txt +0 -11
  232. package/src/commands/manuals/echo.txt +0 -11
  233. package/src/commands/manuals/false.txt +0 -10
  234. package/src/commands/manuals/find.txt +0 -11
  235. package/src/commands/manuals/free.txt +0 -12
  236. package/src/commands/manuals/grep.txt +0 -13
  237. package/src/commands/manuals/groups.txt +0 -10
  238. package/src/commands/manuals/gzip.txt +0 -11
  239. package/src/commands/manuals/head.txt +0 -10
  240. package/src/commands/manuals/help.txt +0 -11
  241. package/src/commands/manuals/history.txt +0 -11
  242. package/src/commands/manuals/hostname.txt +0 -10
  243. package/src/commands/manuals/id.txt +0 -10
  244. package/src/commands/manuals/kill.txt +0 -13
  245. package/src/commands/manuals/ls.txt +0 -20
  246. package/src/commands/manuals/lsb_release.txt +0 -14
  247. package/src/commands/manuals/mkdir.txt +0 -10
  248. package/src/commands/manuals/mv.txt +0 -10
  249. package/src/commands/manuals/nano.txt +0 -11
  250. package/src/commands/manuals/neofetch.txt +0 -10
  251. package/src/commands/manuals/node.txt +0 -13
  252. package/src/commands/manuals/npm.txt +0 -13
  253. package/src/commands/manuals/npx.txt +0 -13
  254. package/src/commands/manuals/passwd.txt +0 -11
  255. package/src/commands/manuals/ping.txt +0 -10
  256. package/src/commands/manuals/printf.txt +0 -11
  257. package/src/commands/manuals/ps.txt +0 -10
  258. package/src/commands/manuals/pwd.txt +0 -10
  259. package/src/commands/manuals/python3.txt +0 -13
  260. package/src/commands/manuals/readlink.txt +0 -10
  261. package/src/commands/manuals/return.txt +0 -10
  262. package/src/commands/manuals/rm.txt +0 -10
  263. package/src/commands/manuals/sed.txt +0 -11
  264. package/src/commands/manuals/set.txt +0 -11
  265. package/src/commands/manuals/shift.txt +0 -10
  266. package/src/commands/manuals/sleep.txt +0 -10
  267. package/src/commands/manuals/sort.txt +0 -12
  268. package/src/commands/manuals/source.txt +0 -11
  269. package/src/commands/manuals/ssh.txt +0 -11
  270. package/src/commands/manuals/stat.txt +0 -10
  271. package/src/commands/manuals/su.txt +0 -13
  272. package/src/commands/manuals/sudo.txt +0 -11
  273. package/src/commands/manuals/tail.txt +0 -10
  274. package/src/commands/manuals/tar.txt +0 -19
  275. package/src/commands/manuals/tee.txt +0 -10
  276. package/src/commands/manuals/test.txt +0 -11
  277. package/src/commands/manuals/touch.txt +0 -11
  278. package/src/commands/manuals/tr.txt +0 -10
  279. package/src/commands/manuals/trap.txt +0 -10
  280. package/src/commands/manuals/true.txt +0 -10
  281. package/src/commands/manuals/type.txt +0 -10
  282. package/src/commands/manuals/uname.txt +0 -12
  283. package/src/commands/manuals/uniq.txt +0 -12
  284. package/src/commands/manuals/unset.txt +0 -10
  285. package/src/commands/manuals/uptime.txt +0 -11
  286. package/src/commands/manuals/wc.txt +0 -12
  287. package/src/commands/manuals/wget.txt +0 -12
  288. package/src/commands/manuals/which.txt +0 -10
  289. package/src/commands/manuals/whoami.txt +0 -10
  290. package/src/commands/manuals/xargs.txt +0 -10
  291. package/src/commands/manuals-bundle.ts +0 -898
  292. package/src/commands/mkdir.ts +0 -31
  293. package/src/commands/mv.ts +0 -50
  294. package/src/commands/nano.ts +0 -38
  295. package/src/commands/neofetch.ts +0 -53
  296. package/src/commands/node.ts +0 -341
  297. package/src/commands/npm.ts +0 -132
  298. package/src/commands/passwd.ts +0 -50
  299. package/src/commands/ping.ts +0 -32
  300. package/src/commands/printf.ts +0 -129
  301. package/src/commands/ps.ts +0 -58
  302. package/src/commands/pwd.ts +0 -9
  303. package/src/commands/python.ts +0 -2229
  304. package/src/commands/read.ts +0 -46
  305. package/src/commands/registry.ts +0 -249
  306. package/src/commands/rm.ts +0 -42
  307. package/src/commands/runtime.ts +0 -421
  308. package/src/commands/sed.ts +0 -68
  309. package/src/commands/seq.ts +0 -43
  310. package/src/commands/set.ts +0 -29
  311. package/src/commands/sh.ts +0 -467
  312. package/src/commands/shift.ts +0 -63
  313. package/src/commands/sleep.ts +0 -20
  314. package/src/commands/sort.ts +0 -46
  315. package/src/commands/source.ts +0 -52
  316. package/src/commands/stat.ts +0 -61
  317. package/src/commands/su.ts +0 -72
  318. package/src/commands/sudo.ts +0 -76
  319. package/src/commands/tail.ts +0 -53
  320. package/src/commands/tar.ts +0 -102
  321. package/src/commands/tee.ts +0 -36
  322. package/src/commands/test.ts +0 -137
  323. package/src/commands/touch.ts +0 -28
  324. package/src/commands/tr.ts +0 -70
  325. package/src/commands/tree.ts +0 -20
  326. package/src/commands/true.ts +0 -27
  327. package/src/commands/type.ts +0 -48
  328. package/src/commands/uname.ts +0 -29
  329. package/src/commands/uniq.ts +0 -39
  330. package/src/commands/unset.ts +0 -17
  331. package/src/commands/uptime.ts +0 -54
  332. package/src/commands/wc.ts +0 -55
  333. package/src/commands/wget.ts +0 -148
  334. package/src/commands/which.ts +0 -37
  335. package/src/commands/who.ts +0 -25
  336. package/src/commands/whoami.ts +0 -14
  337. package/src/commands/xargs.ts +0 -31
  338. package/src/index.ts +0 -67
  339. package/src/modules/linuxRootfs.ts +0 -1961
  340. package/src/modules/neofetch.ts +0 -358
  341. package/src/modules/shellInteractive.ts +0 -57
  342. package/src/modules/shellRuntime.ts +0 -76
  343. package/src/self-standalone.ts +0 -542
  344. package/src/standalone-wo-sftp.ts +0 -38
  345. package/src/standalone.ts +0 -72
  346. package/src/types/commands.ts +0 -146
  347. package/src/types/pipeline.ts +0 -52
  348. package/src/types/streams.ts +0 -32
  349. package/src/types/tar-stream.d.ts +0 -38
  350. package/src/types/vfs.ts +0 -98
  351. package/src/utils/expand.ts +0 -491
  352. package/src/utils/perfLogger.ts +0 -72
  353. package/src/utils/tokenize.ts +0 -98
  354. package/src/utils/vfsDiff.ts +0 -275
  355. package/tests/command-helpers.test.ts +0 -116
  356. package/tests/commands-admin-net.test.ts +0 -441
  357. package/tests/commands-advanced.test.ts +0 -456
  358. package/tests/commands-core.test.ts +0 -562
  359. package/tests/commands-missing.test.ts +0 -570
  360. package/tests/commands-specific-units.test.ts +0 -327
  361. package/tests/commands-text-sys.test.ts +0 -445
  362. package/tests/expand.test.ts +0 -170
  363. package/tests/helpers.test.ts +0 -97
  364. package/tests/new-features.test.ts +0 -1036
  365. package/tests/parser-executor.test.ts +0 -37
  366. package/tests/sftp.test.ts +0 -323
  367. package/tests/ssh-exec.test.ts +0 -45
  368. package/tests/test-helper.ts +0 -79
  369. package/tests/users.test.ts +0 -86
  370. package/tsconfig.json +0 -49
  371. package/typedoc.json +0 -47
@@ -3,6 +3,8 @@ import { aliasCommand, unaliasCommand } from "./alias";
3
3
  import { aptCacheCommand, aptCommand } from "./apt";
4
4
  import { awkCommand } from "./awk";
5
5
  import { base64Command } from "./base64";
6
+ import { basenameCommand, dirnameCommand } from "./basename";
7
+ import { bcCommand } from "./bc";
6
8
  import { catCommand } from "./cat";
7
9
  import { cdCommand } from "./cd";
8
10
  import { chmodCommand } from "./chmod";
@@ -21,8 +23,10 @@ import { echoCommand } from "./echo";
21
23
  import { envCommand } from "./env";
22
24
  import { exitCommand } from "./exit";
23
25
  import { exportCommand } from "./export";
26
+ import { fileCommand } from "./file";
24
27
  import { findCommand } from "./find";
25
28
  import { freeCommand } from "./free";
29
+ import { cmatrixCommand, cowsayCommand, cowthinkCommand, fortuneCommand, slCommand, yesCommand } from "./fun";
26
30
  import { grepCommand } from "./grep";
27
31
  import { groupsCommand } from "./groups";
28
32
  import { gunzipCommand, gzipCommand } from "./gzip";
@@ -32,10 +36,11 @@ import { historyCommand } from "./history";
32
36
  import { hostnameCommand } from "./hostname";
33
37
  import { htopCommand } from "./htop";
34
38
  import { idCommand } from "./id";
39
+ import { ipCommand } from "./ip";
40
+ import { bgCommand, fgCommand, jobsCommand } from "./jobs";
35
41
  import { killCommand } from "./kill";
42
+ import { dmesgCommand, lastCommand } from "./last";
36
43
  import { lnCommand, readlinkCommand } from "./ln";
37
- import { seqCommand } from "./seq";
38
- import { statCommand } from "./stat";
39
44
  import { lsCommand } from "./ls";
40
45
  import { lsbReleaseCommand } from "./lsb-release";
41
46
  import { manCommand } from "./man";
@@ -54,12 +59,14 @@ import { python3Command } from "./python";
54
59
  import { readCommand } from "./read";
55
60
  import { rmCommand } from "./rm";
56
61
  import { sedCommand } from "./sed";
62
+ import { seqCommand } from "./seq";
57
63
  import { setCommand } from "./set";
58
64
  import { shCommand } from "./sh";
59
65
  import { returnCommand, shiftCommand, trapCommand } from "./shift";
60
66
  import { sleepCommand } from "./sleep";
61
67
  import { sortCommand } from "./sort";
62
68
  import { sourceCommand } from "./source";
69
+ import { statCommand } from "./stat";
63
70
  import { suCommand } from "./su";
64
71
  import { sudoCommand } from "./sudo";
65
72
  import { tailCommand } from "./tail";
@@ -67,6 +74,7 @@ import { tarCommand } from "./tar";
67
74
  import { teeCommand } from "./tee";
68
75
  import { testCommand } from "./test";
69
76
  import { touchCommand } from "./touch";
77
+ import { sttyCommand, tputCommand } from "./tput";
70
78
  import { trCommand } from "./tr";
71
79
  import { treeCommand } from "./tree";
72
80
  import { falseCommand, trueCommand } from "./true";
@@ -75,6 +83,7 @@ import { unameCommand } from "./uname";
75
83
  import { uniqCommand } from "./uniq";
76
84
  import { unsetCommand } from "./unset";
77
85
  import { uptimeCommand } from "./uptime";
86
+ import { wCommand } from "./w";
78
87
  import { wcCommand } from "./wc";
79
88
  import { wgetCommand } from "./wget";
80
89
  import { whichCommand } from "./which";
@@ -144,6 +153,21 @@ const BASE_COMMANDS = [
144
153
  exitCommand,
145
154
  // Editors
146
155
  nanoCommand,
156
+ wCommand,
157
+ basenameCommand,
158
+ dirnameCommand,
159
+ fileCommand,
160
+ tputCommand,
161
+ sttyCommand,
162
+ lastCommand,
163
+ dmesgCommand,
164
+ ipCommand,
165
+ yesCommand,
166
+ fortuneCommand,
167
+ cowsayCommand,
168
+ cowthinkCommand,
169
+ cmatrixCommand,
170
+ slCommand,
147
171
  htopCommand,
148
172
  // Network
149
173
  curlCommand,
@@ -162,6 +186,10 @@ const BASE_COMMANDS = [
162
186
  dpkgCommand,
163
187
  dpkgQueryCommand,
164
188
  // Shell (extended)
189
+ jobsCommand,
190
+ bgCommand,
191
+ fgCommand,
192
+ bcCommand,
165
193
  whichCommand,
166
194
  typeCommand,
167
195
  manCommand,
@@ -1,7 +1,7 @@
1
1
  /** biome-ignore-all lint/style/useNamingConvention: ENV VARIABLES */
2
2
  import { executeStatements } from "../SSHMimic/executor";
3
3
  import { parseScript } from "../VirtualShell/shellParser";
4
- import { expandAsync, expandBraces } from "../utils/expand";
4
+ import { expandAsync, expandBraces, expandGlob } from "../utils/expand";
5
5
  import { tokenizeCommand } from "../utils/tokenize";
6
6
  import { resolveModule } from "./registry";
7
7
  /** Returns the home directory path for a given user. Root lives at /root. */
@@ -15,10 +15,11 @@ export function makeDefaultEnv(authUser, hostname) {
15
15
  HOME: userHome(authUser),
16
16
  USER: authUser,
17
17
  LOGNAME: authUser,
18
- SHELL: "/bin/sh",
18
+ SHELL: "/bin/bash",
19
19
  TERM: "xterm-256color",
20
20
  HOSTNAME: hostname,
21
21
  PS1: "\\u@\\h:\\w\\$ ",
22
+ "0": "/bin/bash",
22
23
  },
23
24
  lastExitCode: 0,
24
25
  };
@@ -192,6 +193,26 @@ export async function runCommand(rawInput, authUser, hostname, mode, cwd, shell,
192
193
  return { stderr: `${trimmed.split(" ")[0]}: maximum call depth (${MAX_CALL_DEPTH}) exceeded`, exitCode: 126 };
193
194
  }
194
195
  try {
196
+ // History expansion: !! and !n
197
+ if (trimmed === '!!' || /^!-?\d+$/.test(trimmed) || trimmed.startsWith('!! ')) {
198
+ const histPath = `${shellEnv.vars.HOME ?? `/home/${authUser}`}/.bash_history`;
199
+ if (shell.vfs.exists(histPath)) {
200
+ const lines = shell.vfs.readFile(histPath).split('\n').filter(Boolean);
201
+ let cmd;
202
+ if (trimmed === '!!' || trimmed.startsWith('!! ')) {
203
+ cmd = lines[lines.length - 1];
204
+ }
205
+ else {
206
+ const n = parseInt(trimmed.slice(1), 10);
207
+ cmd = n > 0 ? lines[n - 1] : lines[lines.length + n];
208
+ }
209
+ if (cmd) {
210
+ const suffix = trimmed.startsWith('!! ') ? trimmed.slice(3) : '';
211
+ return runCommand(`${cmd}${suffix ? ` ${suffix}` : ''}`, authUser, hostname, mode, cwd, shell, stdin, shellEnv);
212
+ }
213
+ }
214
+ return { stderr: `${trimmed}: event not found`, exitCode: 1 };
215
+ }
195
216
  const rawTokens = tokenizeCommand(trimmed);
196
217
  const rawFirstWord = rawTokens[0]?.toLowerCase() ?? "";
197
218
  const aliasVal = shellEnv.vars[`__alias_${rawFirstWord}`];
@@ -252,7 +273,7 @@ export async function runCommand(rawInput, authUser, hostname, mode, cwd, shell,
252
273
  }
253
274
  const commandName = parts[0]?.toLowerCase() ?? "";
254
275
  // Apply brace expansion to each arg token
255
- const args = parts.slice(1).flatMap(expandBraces);
276
+ const args = parts.slice(1).flatMap(expandBraces).flatMap(token => expandGlob(token, cwd, shell.vfs));
256
277
  const mod = resolveModule(commandName);
257
278
  if (!mod) {
258
279
  const vfsBinary = resolveVfsBinary(commandName, shellEnv, shell, authUser);
@@ -11,11 +11,31 @@ export const setCommand = {
11
11
  run: ({ args, env }) => {
12
12
  if (args.length === 0) {
13
13
  const out = Object.entries(env.vars)
14
+ .filter(([k]) => !k.startsWith("__"))
14
15
  .map(([k, v]) => `${k}=${v}`)
15
16
  .join("\n");
16
17
  return { stdout: out, exitCode: 0 };
17
18
  }
18
19
  for (const arg of args) {
20
+ const flagMatch = arg.match(/^([+-])([a-zA-Z]+)$/);
21
+ if (flagMatch) {
22
+ const on = flagMatch[1] === "-";
23
+ for (const flag of flagMatch[2]) {
24
+ if (flag === "e") {
25
+ if (on)
26
+ env.vars.__errexit = "1";
27
+ else
28
+ delete env.vars.__errexit;
29
+ }
30
+ if (flag === "x") {
31
+ if (on)
32
+ env.vars.__xtrace = "1";
33
+ else
34
+ delete env.vars.__xtrace;
35
+ }
36
+ }
37
+ continue;
38
+ }
19
39
  if (arg.includes("=")) {
20
40
  const eq = arg.indexOf("=");
21
41
  env.vars[arg.slice(0, eq)] = arg.slice(eq + 1);
@@ -125,6 +125,43 @@ function parseBlocks(lines) {
125
125
  }
126
126
  blocks.push({ type: "while", cond, body });
127
127
  }
128
+ else if (line.startsWith("case ") && line.endsWith(" in") || line.match(/^case\s+.+\s+in$/)) {
129
+ const caseExpr = line.replace(/^case\s+/, "").replace(/\s+in$/, "").trim();
130
+ const patterns = [];
131
+ i++;
132
+ while (i < lines.length && lines[i]?.trim() !== "esac") {
133
+ const pl = lines[i].trim();
134
+ if (!pl || pl === "esac") {
135
+ i++;
136
+ continue;
137
+ }
138
+ // pattern) or pattern1|pattern2)
139
+ const patMatch = pl.match(/^(.+?)\)\s*(.*)$/);
140
+ if (patMatch) {
141
+ const pat = patMatch[1].trim();
142
+ const body = [];
143
+ if (patMatch[2]?.trim() && patMatch[2].trim() !== ";;") {
144
+ body.push(patMatch[2].trim());
145
+ }
146
+ i++;
147
+ while (i < lines.length) {
148
+ const bl = lines[i].trim();
149
+ if (bl === ";;" || bl === "esac")
150
+ break;
151
+ if (bl)
152
+ body.push(bl);
153
+ i++;
154
+ }
155
+ if (lines[i]?.trim() === ";;")
156
+ i++; // skip ;;
157
+ patterns.push({ pattern: pat, body });
158
+ }
159
+ else {
160
+ i++;
161
+ }
162
+ }
163
+ blocks.push({ type: "case", expr: caseExpr, patterns });
164
+ }
128
165
  else {
129
166
  blocks.push({ type: "cmd", line });
130
167
  }
@@ -189,9 +226,12 @@ async function evalCondition(cond, ctx) {
189
226
  async function runBlocks(blocks, ctx) {
190
227
  let lastResult = { exitCode: 0 };
191
228
  let output = "";
229
+ let traceOutput = "";
192
230
  for (const block of blocks) {
193
231
  if (block.type === "cmd") {
194
232
  const expanded = await expandVars(block.line, ctx.env.vars, ctx.env.lastExitCode, ctx);
233
+ if (ctx.env.vars.__xtrace)
234
+ traceOutput += `+ ${expanded}\n`;
195
235
  // Bare VAR=val assignment(s) — handle before dispatching to runCommand
196
236
  const assignRe = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)/;
197
237
  const tokens = expanded.trim().split(/\s+/);
@@ -231,6 +271,8 @@ async function runBlocks(blocks, ctx) {
231
271
  output += `${r.stdout}\n`;
232
272
  if (r.stderr)
233
273
  return { ...r, stdout: output.trim() };
274
+ if (ctx.env.vars.__errexit && (r.exitCode ?? 0) !== 0)
275
+ return { ...r, stdout: output.trim() };
234
276
  lastResult = r;
235
277
  }
236
278
  else if (block.type === "if") {
@@ -311,8 +353,34 @@ async function runBlocks(blocks, ctx) {
311
353
  iterations++;
312
354
  }
313
355
  }
356
+ else if (block.type === "case") {
357
+ const expanded = await expandVars(block.expr, ctx.env.vars, ctx.env.lastExitCode, ctx);
358
+ for (const pat of block.patterns) {
359
+ const alts = pat.pattern.split("|").map((p) => p.trim());
360
+ const matched = alts.some((p) => {
361
+ if (p === "*")
362
+ return true;
363
+ if (p.includes("*") || p.includes("?")) {
364
+ const re = new RegExp(`^${p.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
365
+ return re.test(expanded);
366
+ }
367
+ return p === expanded;
368
+ });
369
+ if (matched) {
370
+ const sub = await runBlocks(parseBlocks(pat.body), ctx);
371
+ if (sub.stdout)
372
+ output += `${sub.stdout}\n`;
373
+ break;
374
+ }
375
+ }
376
+ }
314
377
  }
315
- return { ...lastResult, stdout: output.trim() || lastResult.stdout };
378
+ const finalStdout = output.trim() || lastResult.stdout;
379
+ if (traceOutput) {
380
+ const traceStderr = (lastResult.stderr ? `${lastResult.stderr}\n` : "") + traceOutput.trim();
381
+ return { ...lastResult, stdout: finalStdout, stderr: traceStderr || lastResult.stderr };
382
+ }
383
+ return { ...lastResult, stdout: finalStdout };
316
384
  }
317
385
  /**
318
386
  * Execute shell scripts or commands with a minimal shell interpreter.
@@ -369,6 +437,11 @@ function splitShScript(script) {
369
437
  }
370
438
  continue;
371
439
  }
440
+ // Backslash-newline continuation: join lines
441
+ if (!inSingleQ && ch === '\\' && i + 1 < script.length && script[i + 1] === '\n') {
442
+ i += 2; // skip \ and \n
443
+ continue;
444
+ }
372
445
  if (depth === 0 && (ch === ";" || ch === "\n")) {
373
446
  const t = current.trim();
374
447
  if (t && !t.startsWith("#"))
@@ -0,0 +1,13 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Terminal control.
4
+ * @category shell
5
+ * @params ["<cap> [args...]"]
6
+ */
7
+ export declare const tputCommand: ShellModule;
8
+ /**
9
+ * Print or set terminal line settings.
10
+ * @category shell
11
+ * @params ["[args...]"]
12
+ */
13
+ export declare const sttyCommand: ShellModule;
@@ -0,0 +1,76 @@
1
+ const CAPS = {
2
+ cols: 220, lines: 50, colors: 256,
3
+ bold: "\x1b[1m", dim: "\x1b[2m", smul: "\x1b[4m", rmul: "\x1b[24m",
4
+ rev: "\x1b[7m", smso: "\x1b[7m", rmso: "\x1b[27m",
5
+ sgr0: "\x1b[0m", el: "\x1b[K", ed: "\x1b[J",
6
+ clear: "\x1b[2J\x1b[H", cup: "", setaf: "", setab: "",
7
+ };
8
+ const ANSI_COLORS = [
9
+ "30", "31", "32", "33", "34", "35", "36", "37",
10
+ "90", "91", "92", "93", "94", "95", "96", "97",
11
+ ];
12
+ /**
13
+ * Terminal control.
14
+ * @category shell
15
+ * @params ["<cap> [args...]"]
16
+ */
17
+ export const tputCommand = {
18
+ name: "tput",
19
+ description: "Query terminfo database",
20
+ category: "shell",
21
+ params: ["<cap> [args...]"],
22
+ run: ({ args }) => {
23
+ const cap = args[0];
24
+ if (!cap)
25
+ return { stderr: "tput: missing capability", exitCode: 1 };
26
+ if (cap === "setaf" && args[1] !== undefined) {
27
+ const n = parseInt(args[1], 10);
28
+ const code = ANSI_COLORS[n] ?? "39";
29
+ return { stdout: `\x1b[${code}m`, exitCode: 0 };
30
+ }
31
+ if (cap === "setab" && args[1] !== undefined) {
32
+ const n = parseInt(args[1], 10);
33
+ const code = ANSI_COLORS[n]?.replace(/3/, "4").replace(/9/, "10") ?? "49";
34
+ return { stdout: `\x1b[${code}m`, exitCode: 0 };
35
+ }
36
+ if (cap === "cup" && args[1] !== undefined && args[2] !== undefined) {
37
+ return { stdout: `\x1b[${parseInt(args[1], 10) + 1};${parseInt(args[2], 10) + 1}H`, exitCode: 0 };
38
+ }
39
+ const val = CAPS[cap];
40
+ if (val === undefined)
41
+ return { stderr: `tput: unknown terminal capability '${cap}'`, exitCode: 1 };
42
+ return { stdout: String(val), exitCode: 0 };
43
+ },
44
+ };
45
+ /**
46
+ * Print or set terminal line settings.
47
+ * @category shell
48
+ * @params ["[args...]"]
49
+ */
50
+ export const sttyCommand = {
51
+ name: "stty",
52
+ description: "Change and print terminal line settings",
53
+ category: "shell",
54
+ params: ["[args...]"],
55
+ run: ({ args }) => {
56
+ if (args.includes("-a") || args.includes("--all")) {
57
+ return {
58
+ stdout: [
59
+ "speed 38400 baud; rows 50; columns 220; line = 0;",
60
+ "intr = ^C; quit = ^\\; erase = ^?; kill = ^U; eof = ^D;",
61
+ "eol = M-^?; eol2 = M-^?; swtch = <undef>; start = ^Q; stop = ^S;",
62
+ "-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts",
63
+ "brkint -icrnl ixon -ixoff -iuclc ixany imaxbel -iutf8",
64
+ "opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0",
65
+ "isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke",
66
+ ].join("\n"),
67
+ exitCode: 0,
68
+ };
69
+ }
70
+ if (args.includes("size")) {
71
+ return { stdout: "50 220", exitCode: 0 };
72
+ }
73
+ // silently accept set operations
74
+ return { exitCode: 0 };
75
+ },
76
+ };
@@ -0,0 +1,7 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Show who is logged on and what they are doing.
4
+ * @category system
5
+ * @params ["[user]"]
6
+ */
7
+ export declare const wCommand: ShellModule;
@@ -0,0 +1,38 @@
1
+ import { userHome } from "./runtime";
2
+ /**
3
+ * Show who is logged on and what they are doing.
4
+ * @category system
5
+ * @params ["[user]"]
6
+ */
7
+ export const wCommand = {
8
+ name: "w",
9
+ description: "Show who is logged on and what they are doing",
10
+ category: "system",
11
+ params: ["[user]"],
12
+ run: ({ shell, authUser }) => {
13
+ const now = new Date();
14
+ const upSecs = Math.floor(performance.now() / 1000);
15
+ const upMins = Math.floor(upSecs / 60);
16
+ const upHours = Math.floor(upMins / 60);
17
+ const uptimeStr = upHours > 0
18
+ ? `${upHours}:${String(upMins % 60).padStart(2, "0")}`
19
+ : `${upMins} min`;
20
+ const timeStr = now.toTimeString().slice(0, 5);
21
+ // Read active sessions
22
+ shell.users.listActiveSessions?.();
23
+ const logPath = `${userHome(authUser)}/.lastlog`;
24
+ let loginTime = timeStr;
25
+ if (shell.vfs.exists(logPath)) {
26
+ try {
27
+ const log = JSON.parse(shell.vfs.readFile(logPath));
28
+ loginTime = new Date(log.at).toTimeString().slice(0, 5);
29
+ }
30
+ catch { }
31
+ }
32
+ const header = ` ${timeStr} up ${uptimeStr}, 1 user, load average: 0.${Math.floor(Math.random() * 30).toString().padStart(2, "0")}, 0.${Math.floor(Math.random() * 15).toString().padStart(2, "0")}, 0.${Math.floor(Math.random() * 10).toString().padStart(2, "0")}`;
33
+ const colHeader = "USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT";
34
+ const idle = "0.00s";
35
+ const row = `${authUser.padEnd(8)} pts/0 browser ${loginTime} ${idle} 0.01s 0.00s -bash`;
36
+ return { stdout: [header, colHeader, row].join("\n"), exitCode: 0 };
37
+ },
38
+ };
@@ -56,3 +56,15 @@ export declare function expandSync(input: string, env: Record<string, string>, l
56
56
  * @param runCmd Async callback to execute a command and return its stdout.
57
57
  */
58
58
  export declare function expandAsync(input: string, env: Record<string, string>, lastExit: number, runCmd: (cmd: string) => Promise<string>): Promise<string>;
59
+ /**
60
+ * Expand a glob pattern against a VirtualShell VFS.
61
+ * Supports * (any chars in segment) and ** (any path).
62
+ * Returns the original pattern if no matches found (bash behavior).
63
+ */
64
+ export declare function expandGlob(pattern: string, cwd: string, vfs: {
65
+ list: (p: string) => string[];
66
+ exists: (p: string) => boolean;
67
+ stat: (p: string) => {
68
+ type: string;
69
+ };
70
+ }): string[];
@@ -369,10 +369,12 @@ export function expandSync(input, env, lastExit = 0, home) {
369
369
  let s = chunk;
370
370
  // Tilde expansion — only at start of token or after `:` or whitespace
371
371
  s = s.replace(/(^|[\s:])~(\/|$)/g, (_, pre, post) => `${pre}${homePath}${post}`);
372
- // $? $$ $#
372
+ // $? $$ $# $RANDOM $LINENO
373
373
  s = s.replace(/\$\?/g, String(lastExit));
374
374
  s = s.replace(/\$\$/g, "1");
375
375
  s = s.replace(/\$#/g, "0");
376
+ s = s.replace(/\$RANDOM\b/g, () => String(Math.floor(Math.random() * 32768)));
377
+ s = s.replace(/\$LINENO\b/g, "1");
376
378
  // $(( arithmetic )) — must come before ${ and $VAR to avoid conflicts
377
379
  s = expandArithmeticChunks(s, env);
378
380
  // ${#VAR} — string length
@@ -474,3 +476,87 @@ export async function expandAsync(input, env, lastExit, runCmd) {
474
476
  env[depthKey] = String(currentDepth);
475
477
  }
476
478
  }
479
+ // ─── Glob expansion ──────────────────────────────────────────────────────────
480
+ /**
481
+ * Expand a glob pattern against a VirtualShell VFS.
482
+ * Supports * (any chars in segment) and ** (any path).
483
+ * Returns the original pattern if no matches found (bash behavior).
484
+ */
485
+ export function expandGlob(pattern, cwd, vfs) {
486
+ // No glob chars → return as-is
487
+ if (!pattern.includes('*') && !pattern.includes('?'))
488
+ return [pattern];
489
+ const isAbsolute = pattern.startsWith('/');
490
+ const base = isAbsolute ? '/' : cwd;
491
+ const relPattern = isAbsolute ? pattern.slice(1) : pattern;
492
+ const results = matchGlob(base, relPattern.split('/'), vfs);
493
+ if (results.length === 0)
494
+ return [pattern]; // no match → literal
495
+ return results.sort();
496
+ }
497
+ function matchGlob(dir, segments, vfs) {
498
+ if (segments.length === 0)
499
+ return [dir];
500
+ const [seg, ...rest] = segments;
501
+ if (!seg)
502
+ return [dir];
503
+ // ** matches zero or more path segments
504
+ if (seg === '**') {
505
+ const all = walkAll(dir, vfs);
506
+ return rest.length === 0 ? all : all.flatMap(d => {
507
+ try {
508
+ if (vfs.stat(d).type === 'directory')
509
+ return matchGlob(d, rest, vfs);
510
+ }
511
+ catch { }
512
+ return [];
513
+ });
514
+ }
515
+ let entries = [];
516
+ try {
517
+ entries = vfs.list(dir);
518
+ }
519
+ catch {
520
+ return [];
521
+ }
522
+ const re = globToRegex(seg);
523
+ return entries
524
+ .filter(e => !e.startsWith('.') || seg.startsWith('.'))
525
+ .filter(e => re.test(e))
526
+ .flatMap(e => {
527
+ const full = dir === '/' ? `/${e}` : `${dir}/${e}`;
528
+ if (rest.length === 0)
529
+ return [full];
530
+ try {
531
+ if (vfs.stat(full).type === 'directory')
532
+ return matchGlob(full, rest, vfs);
533
+ }
534
+ catch { }
535
+ return [];
536
+ });
537
+ }
538
+ function walkAll(dir, vfs) {
539
+ const results = [dir];
540
+ let entries = [];
541
+ try {
542
+ entries = vfs.list(dir);
543
+ }
544
+ catch {
545
+ return results;
546
+ }
547
+ for (const e of entries) {
548
+ const full = dir === '/' ? `/${e}` : `${dir}/${e}`;
549
+ try {
550
+ if (vfs.stat(full).type === 'directory')
551
+ results.push(...walkAll(full, vfs));
552
+ }
553
+ catch { }
554
+ }
555
+ return results;
556
+ }
557
+ function globToRegex(pattern) {
558
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&')
559
+ .replace(/\*/g, '.*')
560
+ .replace(/\?/g, '.');
561
+ return new RegExp(`^${escaped}$`);
562
+ }
package/package.json CHANGED
@@ -4,7 +4,13 @@
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
7
- "version": "1.5.3",
7
+ "version": "1.5.5",
8
+ "files": [
9
+ "dist/",
10
+ "README.md",
11
+ "LICENSE",
12
+ "CHANGELOG.md"
13
+ ],
8
14
  "license": "MIT",
9
15
  "repository": {
10
16
  "type": "git",
@@ -26,7 +32,7 @@
26
32
  "lint:write": "bunx --bun @biomejs/biome lint --write ./src",
27
33
  "test": "bun run test-salve",
28
34
  "test-battery": "bun test tests/",
29
- "test-salve": "for f in tests/*.test.ts; do echo \"\\n🧪 Testing $f...\"; bun test \"$f\" --timeout 10000; sleep 0.25; done",
35
+ "test-salve": "for f in tests/*.test.ts; do echo \"\\n\ud83e\uddea Testing $f...\"; bun test \"$f\" --timeout 10000; sleep 0.25; done",
30
36
  "build": "tsc --project tsconfig.json",
31
37
  "deploy:npm": "bun publish --access public",
32
38
  "bench": "rm -rf .benchmark-shells/ && bun benchmark-virtualshell.ts",
@@ -59,4 +65,4 @@
59
65
  "dependencies": {
60
66
  "ssh2": "^1.17.0"
61
67
  }
62
- }
68
+ }
@@ -1,50 +0,0 @@
1
- name: Bug report
2
- description: Report a reproducible problem
3
- labels: [bug]
4
- body:
5
- - type: markdown
6
- attributes:
7
- value: |
8
- Thanks for reporting a bug. Please fill out the details below.
9
- - type: input
10
- id: version
11
- attributes:
12
- label: Package version
13
- placeholder: 1.0.0
14
- validations:
15
- required: true
16
- - type: input
17
- id: runtime
18
- attributes:
19
- label: Runtime and version
20
- description: Node or Bun
21
- placeholder: Node 20.12.0
22
- validations:
23
- required: true
24
- - type: textarea
25
- id: reproduction
26
- attributes:
27
- label: Reproduction steps
28
- placeholder: |
29
- 1. Start server with ...
30
- 2. Run command ...
31
- 3. Observe error ...
32
- validations:
33
- required: true
34
- - type: textarea
35
- id: expected
36
- attributes:
37
- label: Expected behavior
38
- validations:
39
- required: true
40
- - type: textarea
41
- id: actual
42
- attributes:
43
- label: Actual behavior
44
- validations:
45
- required: true
46
- - type: textarea
47
- id: logs
48
- attributes:
49
- label: Logs or stack trace
50
- render: shell
@@ -1,31 +0,0 @@
1
- name: Feature request
2
- description: Suggest an improvement
3
- labels: [enhancement]
4
- body:
5
- - type: markdown
6
- attributes:
7
- value: |
8
- Thanks for proposing an improvement.
9
- - type: textarea
10
- id: problem
11
- attributes:
12
- label: Problem statement
13
- description: What problem are you trying to solve?
14
- validations:
15
- required: true
16
- - type: textarea
17
- id: proposal
18
- attributes:
19
- label: Proposed solution
20
- description: Describe the API or behavior you want.
21
- validations:
22
- required: true
23
- - type: textarea
24
- id: alternatives
25
- attributes:
26
- label: Alternatives considered
27
- - type: textarea
28
- id: impact
29
- attributes:
30
- label: Breaking change impact
31
- description: Does this change public API behavior?