buninu-linux 0.2.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 (621) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES/Bun-LICENSE.md +84 -0
  3. package/LICENSES/GCC-Runtime-Library-Exception-3.1.txt +73 -0
  4. package/LICENSES/GPL-2.0.txt +338 -0
  5. package/LICENSES/GPL-3.0.txt +674 -0
  6. package/LICENSES/LGPL-2.1.txt +501 -0
  7. package/LICENSES/Linux-syscall-note.txt +25 -0
  8. package/LICENSES/musl-COPYRIGHT.txt +193 -0
  9. package/NOTICE.md +184 -0
  10. package/README.md +537 -0
  11. package/build-image.sh +44 -0
  12. package/build-uki.sh +75 -0
  13. package/fetch-alpine.sh +80 -0
  14. package/fetch-bun.sh +41 -0
  15. package/fetch-plus-build.sh +11 -0
  16. package/hello/build-hello.sh +14 -0
  17. package/hello/hello.c +50 -0
  18. package/index.js +235 -0
  19. package/initramfs/bin/sh +3 -0
  20. package/initramfs/buninu/.bashrc +11 -0
  21. package/initramfs/buninu/ARCHITECTURE.md +452 -0
  22. package/initramfs/buninu/CHANGELOG.md +580 -0
  23. package/initramfs/buninu/LICENSE +21 -0
  24. package/initramfs/buninu/README.md +1161 -0
  25. package/initramfs/buninu/apps/bun/make-bunBin.sh +99 -0
  26. package/initramfs/buninu/apps/bunmsh/CHANGELOG.md +493 -0
  27. package/initramfs/buninu/apps/bunmsh/LICENSE +21 -0
  28. package/initramfs/buninu/apps/bunmsh/LICENSE-MICRO +58 -0
  29. package/initramfs/buninu/apps/bunmsh/LICENSE-MKSH +295 -0
  30. package/initramfs/buninu/apps/bunmsh/PORTING.md +192 -0
  31. package/initramfs/buninu/apps/bunmsh/README.md +1042 -0
  32. package/initramfs/buninu/apps/bunmsh/bunmsh +7 -0
  33. package/initramfs/buninu/apps/bunmsh/bunshell.md +61 -0
  34. package/initramfs/buninu/apps/bunmsh/help/README.md +2237 -0
  35. package/initramfs/buninu/apps/bunmsh/help/alias.md +22 -0
  36. package/initramfs/buninu/apps/bunmsh/help/basename.md +38 -0
  37. package/initramfs/buninu/apps/bunmsh/help/builtin.md +25 -0
  38. package/initramfs/buninu/apps/bunmsh/help/bun.md +27 -0
  39. package/initramfs/buninu/apps/bunmsh/help/bunmsh.md +47 -0
  40. package/initramfs/buninu/apps/bunmsh/help/cat.md +31 -0
  41. package/initramfs/buninu/apps/bunmsh/help/catfancy.md +35 -0
  42. package/initramfs/buninu/apps/bunmsh/help/cd.md +22 -0
  43. package/initramfs/buninu/apps/bunmsh/help/chmod.md +27 -0
  44. package/initramfs/buninu/apps/bunmsh/help/clear.md +21 -0
  45. package/initramfs/buninu/apps/bunmsh/help/colon.md +22 -0
  46. package/initramfs/buninu/apps/bunmsh/help/command.md +27 -0
  47. package/initramfs/buninu/apps/bunmsh/help/cp.md +28 -0
  48. package/initramfs/buninu/apps/bunmsh/help/curl.md +181 -0
  49. package/initramfs/buninu/apps/bunmsh/help/cut.md +25 -0
  50. package/initramfs/buninu/apps/bunmsh/help/date.md +25 -0
  51. package/initramfs/buninu/apps/bunmsh/help/dirname.md +25 -0
  52. package/initramfs/buninu/apps/bunmsh/help/echo.md +25 -0
  53. package/initramfs/buninu/apps/bunmsh/help/env.md +27 -0
  54. package/initramfs/buninu/apps/bunmsh/help/eval.md +22 -0
  55. package/initramfs/buninu/apps/bunmsh/help/exec.md +22 -0
  56. package/initramfs/buninu/apps/bunmsh/help/exit.md +21 -0
  57. package/initramfs/buninu/apps/bunmsh/help/export.md +22 -0
  58. package/initramfs/buninu/apps/bunmsh/help/false.md +22 -0
  59. package/initramfs/buninu/apps/bunmsh/help/find.md +33 -0
  60. package/initramfs/buninu/apps/bunmsh/help/getopts.md +28 -0
  61. package/initramfs/buninu/apps/bunmsh/help/grep.md +34 -0
  62. package/initramfs/buninu/apps/bunmsh/help/head.md +27 -0
  63. package/initramfs/buninu/apps/bunmsh/help/kill.md +43 -0
  64. package/initramfs/buninu/apps/bunmsh/help/ln.md +28 -0
  65. package/initramfs/buninu/apps/bunmsh/help/ls.md +37 -0
  66. package/initramfs/buninu/apps/bunmsh/help/lsbun.md +29 -0
  67. package/initramfs/buninu/apps/bunmsh/help/lsfancy.md +37 -0
  68. package/initramfs/buninu/apps/bunmsh/help/md5sum.md +21 -0
  69. package/initramfs/buninu/apps/bunmsh/help/mkdir.md +27 -0
  70. package/initramfs/buninu/apps/bunmsh/help/mktemp.md +26 -0
  71. package/initramfs/buninu/apps/bunmsh/help/mv.md +26 -0
  72. package/initramfs/buninu/apps/bunmsh/help/print.md +30 -0
  73. package/initramfs/buninu/apps/bunmsh/help/printf.md +25 -0
  74. package/initramfs/buninu/apps/bunmsh/help/pspa.md +38 -0
  75. package/initramfs/buninu/apps/bunmsh/help/pspac.md +57 -0
  76. package/initramfs/buninu/apps/bunmsh/help/pwd.md +21 -0
  77. package/initramfs/buninu/apps/bunmsh/help/read.md +27 -0
  78. package/initramfs/buninu/apps/bunmsh/help/readonly.md +27 -0
  79. package/initramfs/buninu/apps/bunmsh/help/realpath.md +21 -0
  80. package/initramfs/buninu/apps/bunmsh/help/rm.md +33 -0
  81. package/initramfs/buninu/apps/bunmsh/help/rmdir.md +27 -0
  82. package/initramfs/buninu/apps/bunmsh/help/sed.md +29 -0
  83. package/initramfs/buninu/apps/bunmsh/help/seq.md +29 -0
  84. package/initramfs/buninu/apps/bunmsh/help/serve.md +50 -0
  85. package/initramfs/buninu/apps/bunmsh/help/set.md +26 -0
  86. package/initramfs/buninu/apps/bunmsh/help/sha256sum.md +21 -0
  87. package/initramfs/buninu/apps/bunmsh/help/shift.md +23 -0
  88. package/initramfs/buninu/apps/bunmsh/help/sleep.md +25 -0
  89. package/initramfs/buninu/apps/bunmsh/help/sort.md +29 -0
  90. package/initramfs/buninu/apps/bunmsh/help/source.md +23 -0
  91. package/initramfs/buninu/apps/bunmsh/help/tab.md +30 -0
  92. package/initramfs/buninu/apps/bunmsh/help/tac.md +29 -0
  93. package/initramfs/buninu/apps/bunmsh/help/tail.md +27 -0
  94. package/initramfs/buninu/apps/bunmsh/help/tee.md +25 -0
  95. package/initramfs/buninu/apps/bunmsh/help/test.md +30 -0
  96. package/initramfs/buninu/apps/bunmsh/help/time.md +29 -0
  97. package/initramfs/buninu/apps/bunmsh/help/touch.md +26 -0
  98. package/initramfs/buninu/apps/bunmsh/help/tr.md +26 -0
  99. package/initramfs/buninu/apps/bunmsh/help/true.md +22 -0
  100. package/initramfs/buninu/apps/bunmsh/help/type.md +21 -0
  101. package/initramfs/buninu/apps/bunmsh/help/umask.md +22 -0
  102. package/initramfs/buninu/apps/bunmsh/help/unalias.md +28 -0
  103. package/initramfs/buninu/apps/bunmsh/help/uname.md +31 -0
  104. package/initramfs/buninu/apps/bunmsh/help/unset.md +28 -0
  105. package/initramfs/buninu/apps/bunmsh/help/wc.md +27 -0
  106. package/initramfs/buninu/apps/bunmsh/help/whence.md +26 -0
  107. package/initramfs/buninu/apps/bunmsh/help/which.md +41 -0
  108. package/initramfs/buninu/apps/bunmsh/help/yes.md +23 -0
  109. package/initramfs/buninu/apps/bunmsh/index.js +7 -0
  110. package/initramfs/buninu/apps/bunmsh/package.json +30 -0
  111. package/initramfs/buninu/apps/bunmsh/serve.js +468 -0
  112. package/initramfs/buninu/apps/bunmsh/single-exe/README.md +402 -0
  113. package/initramfs/buninu/apps/bunmsh/single-exe/assetsHelper.js +371 -0
  114. package/initramfs/buninu/apps/bunmsh/single-exe/assetsLoader.mjs +85 -0
  115. package/initramfs/buninu/apps/bunmsh/single-exe/assetsPacker.js +218 -0
  116. package/initramfs/buninu/apps/bunmsh/single-exe/compiled.js +527 -0
  117. package/initramfs/buninu/apps/bunmsh/single-exe/entry.mjs +17 -0
  118. package/initramfs/buninu/apps/bunmsh/src/cat-fancy.js +117 -0
  119. package/initramfs/buninu/apps/bunmsh/src/cat-operands.js +31 -0
  120. package/initramfs/buninu/apps/bunmsh/src/completion.js +363 -0
  121. package/initramfs/buninu/apps/bunmsh/src/curl.js +1191 -0
  122. package/initramfs/buninu/apps/bunmsh/src/environment.js +61 -0
  123. package/initramfs/buninu/apps/bunmsh/src/fancy-ls.js +186 -0
  124. package/initramfs/buninu/apps/bunmsh/src/find.js +119 -0
  125. package/initramfs/buninu/apps/bunmsh/src/history.js +198 -0
  126. package/initramfs/buninu/apps/bunmsh/src/main.js +850 -0
  127. package/initramfs/buninu/apps/bunmsh/src/mouse.js +103 -0
  128. package/initramfs/buninu/apps/bunmsh/src/shell.js +3932 -0
  129. package/initramfs/buninu/apps/bunmsh/test/catfancy.test.js +102 -0
  130. package/initramfs/buninu/apps/bunmsh/test/curl.test.js +335 -0
  131. package/initramfs/buninu/apps/bunmsh/test/reference-source.sh +1 -0
  132. package/initramfs/buninu/apps/bunmsh/test/reference.test.js +817 -0
  133. package/initramfs/buninu/apps/bunmsh/test/serve/README.md +3 -0
  134. package/initramfs/buninu/apps/bunmsh/test/serve/bad.json +1 -0
  135. package/initramfs/buninu/apps/bunmsh/test/serve/data.json +1 -0
  136. package/initramfs/buninu/apps/bunmsh/test/serve/data.json5 +1 -0
  137. package/initramfs/buninu/apps/bunmsh/test/serve/data.jsonc +2 -0
  138. package/initramfs/buninu/apps/bunmsh/test/serve/data.jsonl +2 -0
  139. package/initramfs/buninu/apps/bunmsh/test/serve/data.ndjson +1 -0
  140. package/initramfs/buninu/apps/bunmsh/test/serve/data.toml +3 -0
  141. package/initramfs/buninu/apps/bunmsh/test/serve/data.ts +15 -0
  142. package/initramfs/buninu/apps/bunmsh/test/serve/data.xml +1 -0
  143. package/initramfs/buninu/apps/bunmsh/test/serve/data.yaml +3 -0
  144. package/initramfs/buninu/apps/bunmsh/test/serve/data.yml +1 -0
  145. package/initramfs/buninu/apps/bunmsh/test/serve.test.js +241 -0
  146. package/initramfs/buninu/apps/bunmsh/test/shell.test.js +2092 -0
  147. package/initramfs/buninu/apps/bunmsh/test/shell1.test.js +1087 -0
  148. package/initramfs/buninu/apps/bunmsh/test/shell2.test.js +457 -0
  149. package/initramfs/buninu/apps/bunmsh/test/shell3.test.js +741 -0
  150. package/initramfs/buninu/apps/bunmsh/test/t.sh +12 -0
  151. package/initramfs/buninu/apps/bunx/bunx.js +172 -0
  152. package/initramfs/buninu/apps/cmdlist +48 -0
  153. package/initramfs/buninu/apps/jsgotty/LICENSE +23 -0
  154. package/initramfs/buninu/apps/jsgotty/LICENSES/Apache-2.0-zmodem.js.txt +201 -0
  155. package/initramfs/buninu/apps/jsgotty/NOTICE +21 -0
  156. package/initramfs/buninu/apps/jsgotty/README.en.md +294 -0
  157. package/initramfs/buninu/apps/jsgotty/README.md +296 -0
  158. package/initramfs/buninu/apps/jsgotty/client.mjs +700 -0
  159. package/initramfs/buninu/apps/jsgotty/env.sh +2 -0
  160. package/initramfs/buninu/apps/jsgotty/gotty.js +3334 -0
  161. package/initramfs/buninu/apps/jsgotty/node_modules/.package-lock.json +35 -0
  162. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/LICENSE.md +9 -0
  163. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/README.md +319 -0
  164. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/common.gypi +20 -0
  165. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/except.gypi +25 -0
  166. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/index.js +12 -0
  167. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  168. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/napi-inl.h +6607 -0
  169. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/napi.h +3201 -0
  170. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/node_addon_api.gyp +32 -0
  171. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/node_api.gyp +9 -0
  172. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/noexcept.gypi +26 -0
  173. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/nothing.c +0 -0
  174. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/package-support.json +21 -0
  175. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/package.json +480 -0
  176. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/tools/README.md +73 -0
  177. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/tools/check-napi.js +99 -0
  178. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/tools/clang-format.js +71 -0
  179. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/tools/conversion.js +301 -0
  180. package/initramfs/buninu/apps/jsgotty/node_modules/node-addon-api/tools/eslint-format.js +79 -0
  181. package/initramfs/buninu/apps/jsgotty/node_modules/ws/LICENSE +20 -0
  182. package/initramfs/buninu/apps/jsgotty/node_modules/ws/README.md +548 -0
  183. package/initramfs/buninu/apps/jsgotty/node_modules/ws/browser.js +8 -0
  184. package/initramfs/buninu/apps/jsgotty/node_modules/ws/index.js +22 -0
  185. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/buffer-util.js +131 -0
  186. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/constants.js +19 -0
  187. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/event-target.js +292 -0
  188. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/extension.js +203 -0
  189. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/limiter.js +55 -0
  190. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/permessage-deflate.js +528 -0
  191. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/receiver.js +760 -0
  192. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/sender.js +607 -0
  193. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/stream.js +161 -0
  194. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/subprotocol.js +62 -0
  195. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/validation.js +152 -0
  196. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/websocket-server.js +562 -0
  197. package/initramfs/buninu/apps/jsgotty/node_modules/ws/lib/websocket.js +1407 -0
  198. package/initramfs/buninu/apps/jsgotty/node_modules/ws/package.json +70 -0
  199. package/initramfs/buninu/apps/jsgotty/node_modules/ws/wrapper.mjs +21 -0
  200. package/initramfs/buninu/apps/jsgotty/package-lock.json +46 -0
  201. package/initramfs/buninu/apps/jsgotty/package.json +19 -0
  202. package/initramfs/buninu/apps/jsgotty/patches/windowsPtyAgent.js +326 -0
  203. package/initramfs/buninu/apps/jsgotty/patches/windowsTerminal.js +204 -0
  204. package/initramfs/buninu/apps/jsgotty/rz.js +199 -0
  205. package/initramfs/buninu/apps/jsgotty/single-exe/README.md +384 -0
  206. package/initramfs/buninu/apps/jsgotty/single-exe/assetsHelper.js +371 -0
  207. package/initramfs/buninu/apps/jsgotty/single-exe/assetsLoader.mjs +85 -0
  208. package/initramfs/buninu/apps/jsgotty/single-exe/assetsPacker.js +218 -0
  209. package/initramfs/buninu/apps/jsgotty/single-exe/compiled.js +498 -0
  210. package/initramfs/buninu/apps/jsgotty/single-exe/entry.mjs +23 -0
  211. package/initramfs/buninu/apps/jsgotty/single-exe/packAssets.sh +7 -0
  212. package/initramfs/buninu/apps/jsgotty/static/css/index.css +13 -0
  213. package/initramfs/buninu/apps/jsgotty/static/css/kitty.css +61 -0
  214. package/initramfs/buninu/apps/jsgotty/static/css/xterm.css +218 -0
  215. package/initramfs/buninu/apps/jsgotty/static/css/xterm_customize.css +35 -0
  216. package/initramfs/buninu/apps/jsgotty/static/favicon.ico +0 -0
  217. package/initramfs/buninu/apps/jsgotty/static/help.md +125 -0
  218. package/initramfs/buninu/apps/jsgotty/static/icon.svg +66 -0
  219. package/initramfs/buninu/apps/jsgotty/static/icon_192.png +0 -0
  220. package/initramfs/buninu/apps/jsgotty/static/index.html +164 -0
  221. package/initramfs/buninu/apps/jsgotty/static/js/gotty.js +31537 -0
  222. package/initramfs/buninu/apps/jsgotty/static/js/gotty.js.LICENSE.txt +7 -0
  223. package/initramfs/buninu/apps/jsgotty/static/js/gotty.js.map +1 -0
  224. package/initramfs/buninu/apps/jsgotty/static/js/gotty.licenses.txt +650 -0
  225. package/initramfs/buninu/apps/jsgotty/static/js/kitty.js +1101 -0
  226. package/initramfs/buninu/apps/jsgotty/static/js/windows_bridge.js +194 -0
  227. package/initramfs/buninu/apps/jsgotty/static/js/xterm-addon-unicode11.js +2 -0
  228. package/initramfs/buninu/apps/jsgotty/static/js/zmodem.js +1 -0
  229. package/initramfs/buninu/apps/jsgotty/static/manifest.json +15 -0
  230. package/initramfs/buninu/apps/jsgotty/sz.js +273 -0
  231. package/initramfs/buninu/apps/jsgotty/tests/kitty-order.test.js +58 -0
  232. package/initramfs/buninu/apps/jsgotty/tests/websocket-origin.test.js +54 -0
  233. package/initramfs/buninu/apps/jsgotty/viu.mjs +422 -0
  234. package/initramfs/buninu/apps/jsgotty/wgotty +62 -0
  235. package/initramfs/buninu/apps/jsgotty/windows-bridge-node.js +60 -0
  236. package/initramfs/buninu/apps/jsgotty/zmodem-node.js +262 -0
  237. package/initramfs/buninu/apps/jsmdcui/CHANGELOG.md +1118 -0
  238. package/initramfs/buninu/apps/jsmdcui/LICENSE +22 -0
  239. package/initramfs/buninu/apps/jsmdcui/README.md +1283 -0
  240. package/initramfs/buninu/apps/jsmdcui/cdp-maze.js +141 -0
  241. package/initramfs/buninu/apps/jsmdcui/clean.sh +9 -0
  242. package/initramfs/buninu/apps/jsmdcui/demos/basic.jpg +0 -0
  243. package/initramfs/buninu/apps/jsmdcui/demos/chinese.md +32 -0
  244. package/initramfs/buninu/apps/jsmdcui/demos/event.md +170 -0
  245. package/initramfs/buninu/apps/jsmdcui/demos/good.jpg +0 -0
  246. package/initramfs/buninu/apps/jsmdcui/demos/image-processor.md +366 -0
  247. package/initramfs/buninu/apps/jsmdcui/demos/image-processor.zh-TW.md +366 -0
  248. package/initramfs/buninu/apps/jsmdcui/demos/img-change.md +73 -0
  249. package/initramfs/buninu/apps/jsmdcui/demos/imgtool-zh.md +298 -0
  250. package/initramfs/buninu/apps/jsmdcui/demos/imgtool.md +298 -0
  251. package/initramfs/buninu/apps/jsmdcui/demos/maze.md +149 -0
  252. package/initramfs/buninu/apps/jsmdcui/demos/reactive.md +40 -0
  253. package/initramfs/buninu/apps/jsmdcui/demos/reader.md +513 -0
  254. package/initramfs/buninu/apps/jsmdcui/demos/select.md +63 -0
  255. package/initramfs/buninu/apps/jsmdcui/demos/todo-zh.md +190 -0
  256. package/initramfs/buninu/apps/jsmdcui/demos/todo.md +191 -0
  257. package/initramfs/buninu/apps/jsmdcui/edit +9 -0
  258. package/initramfs/buninu/apps/jsmdcui/jsmdcui.sh +16 -0
  259. package/initramfs/buninu/apps/jsmdcui/llm-maze.txt +94 -0
  260. package/initramfs/buninu/apps/jsmdcui/package.json +29 -0
  261. package/initramfs/buninu/apps/jsmdcui/project_structure.txt +35 -0
  262. package/initramfs/buninu/apps/jsmdcui/runmd.mjs +1140 -0
  263. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/atom-dark.micro +33 -0
  264. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/bubblegum.micro +31 -0
  265. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/cmc-16.micro +47 -0
  266. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/cmc-tc.micro +43 -0
  267. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/darcula.micro +34 -0
  268. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/default.micro +1 -0
  269. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/dracula-tc.micro +49 -0
  270. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/dukedark-tc.micro +38 -0
  271. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/dukelight-tc.micro +38 -0
  272. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/dukeubuntu-tc.micro +38 -0
  273. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/geany.micro +29 -0
  274. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/gotham.micro +29 -0
  275. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/gruvbox-tc.micro +29 -0
  276. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/gruvbox.micro +26 -0
  277. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/material-tc.micro +36 -0
  278. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/monokai-dark.micro +28 -0
  279. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/monokai.micro +34 -0
  280. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/one-dark.micro +39 -0
  281. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/railscast.micro +37 -0
  282. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/simple.micro +33 -0
  283. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/solarized-tc.micro +31 -0
  284. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/solarized.micro +30 -0
  285. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/sunny-day.micro +29 -0
  286. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/twilight.micro +40 -0
  287. package/initramfs/buninu/apps/jsmdcui/runtime/colorschemes/zenburn.micro +30 -0
  288. package/initramfs/buninu/apps/jsmdcui/runtime/help/actions.md +161 -0
  289. package/initramfs/buninu/apps/jsmdcui/runtime/help/cdp.md +130 -0
  290. package/initramfs/buninu/apps/jsmdcui/runtime/help/colors.md +421 -0
  291. package/initramfs/buninu/apps/jsmdcui/runtime/help/commands.md +161 -0
  292. package/initramfs/buninu/apps/jsmdcui/runtime/help/copypaste.md +149 -0
  293. package/initramfs/buninu/apps/jsmdcui/runtime/help/defaultkeys.md +148 -0
  294. package/initramfs/buninu/apps/jsmdcui/runtime/help/help.md +1283 -0
  295. package/initramfs/buninu/apps/jsmdcui/runtime/help/keybindings.md +355 -0
  296. package/initramfs/buninu/apps/jsmdcui/runtime/help/linter.md +90 -0
  297. package/initramfs/buninu/apps/jsmdcui/runtime/help/options.md +709 -0
  298. package/initramfs/buninu/apps/jsmdcui/runtime/help/plugins.md +544 -0
  299. package/initramfs/buninu/apps/jsmdcui/runtime/help/tutorial.md +112 -0
  300. package/initramfs/buninu/apps/jsmdcui/runtime/jsplugins/cdp/cdp-server.js +1263 -0
  301. package/initramfs/buninu/apps/jsmdcui/runtime/jsplugins/cdp/cdp.js +203 -0
  302. package/initramfs/buninu/apps/jsmdcui/runtime/jsplugins/chapter/chapter.js +111 -0
  303. package/initramfs/buninu/apps/jsmdcui/runtime/jsplugins/diff/diff.js +46 -0
  304. package/initramfs/buninu/apps/jsmdcui/runtime/jsplugins/example/example.js +117 -0
  305. package/initramfs/buninu/apps/jsmdcui/runtime/jsplugins/linter/linter.js +281 -0
  306. package/initramfs/buninu/apps/jsmdcui/runtime/plugins/autoclose/autoclose.lua +75 -0
  307. package/initramfs/buninu/apps/jsmdcui/runtime/plugins/ftoptions/ftoptions.lua +17 -0
  308. package/initramfs/buninu/apps/jsmdcui/runtime/plugins/literate/README.md +5 -0
  309. package/initramfs/buninu/apps/jsmdcui/runtime/plugins/literate/literate.lua +55 -0
  310. package/initramfs/buninu/apps/jsmdcui/runtime/plugins/status/help/status.md +21 -0
  311. package/initramfs/buninu/apps/jsmdcui/runtime/plugins/status/status.lua +62 -0
  312. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/LICENSE +22 -0
  313. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/PowerShell.yaml +128 -0
  314. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/README.md +63 -0
  315. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/ada.yaml +43 -0
  316. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/apacheconf.yaml +59 -0
  317. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/arduino.yaml +101 -0
  318. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/asciidoc.yaml +51 -0
  319. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/asm.yaml +123 -0
  320. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/ats.yaml +99 -0
  321. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/awk.yaml +44 -0
  322. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/b.yaml +87 -0
  323. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/bat.yaml +57 -0
  324. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/c.yaml +60 -0
  325. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/caddyfile.yaml +23 -0
  326. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/cake.yaml +7 -0
  327. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/clojure.yaml +38 -0
  328. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/cmake.yaml +42 -0
  329. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/coffeescript.yaml +56 -0
  330. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/colortest.yaml +19 -0
  331. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/conky.yaml +17 -0
  332. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/cpp.yaml +91 -0
  333. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/crontab.yaml +36 -0
  334. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/crystal.yaml +72 -0
  335. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/csharp.yaml +52 -0
  336. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/css.yaml +44 -0
  337. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/csx.yaml +8 -0
  338. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/cuda.yaml +68 -0
  339. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/cython.yaml +52 -0
  340. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/d.yaml +121 -0
  341. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/dart.yaml +46 -0
  342. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/default.yaml +10 -0
  343. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/dockerfile.yaml +36 -0
  344. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/dot.yaml +29 -0
  345. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/elixir.yaml +30 -0
  346. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/elm.yaml +38 -0
  347. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/erb.yaml +42 -0
  348. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/erlang.yaml +45 -0
  349. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/fish.yaml +48 -0
  350. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/forth.yaml +34 -0
  351. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/fortran.yaml +64 -0
  352. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/freebsd-kernel.yaml +14 -0
  353. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/fsharp.yaml +48 -0
  354. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/gdscript.yaml +61 -0
  355. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/gemini.yaml +19 -0
  356. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/gentoo-ebuild.yaml +48 -0
  357. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/gentoo-etc-portage.yaml +23 -0
  358. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/git-commit.yaml +35 -0
  359. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/git-config.yaml +14 -0
  360. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/git-rebase-todo.yaml +19 -0
  361. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/gleam.yaml +69 -0
  362. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/glsl.yaml +26 -0
  363. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/gnuplot.yaml +15 -0
  364. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/go.yaml +62 -0
  365. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/godoc.yaml +17 -0
  366. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/golo.yaml +73 -0
  367. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/gomod.yaml +31 -0
  368. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/graphql.yaml +47 -0
  369. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/groff.yaml +30 -0
  370. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/groovy.yaml +111 -0
  371. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/haml.yaml +16 -0
  372. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/hare.yaml +52 -0
  373. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/haskell.yaml +52 -0
  374. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/hc.yaml +52 -0
  375. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/html.yaml +70 -0
  376. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/html4.yaml +25 -0
  377. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/html5.yaml +25 -0
  378. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/ini.yaml +23 -0
  379. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/inputrc.yaml +14 -0
  380. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/java.yaml +37 -0
  381. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/javascript.yaml +124 -0
  382. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/jinja2.yaml +19 -0
  383. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/json.yaml +39 -0
  384. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/jsonnet.yaml +92 -0
  385. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/julia.yaml +57 -0
  386. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/justfile.yaml +40 -0
  387. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/keymap.yaml +27 -0
  388. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/kickstart.yaml +16 -0
  389. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/kotlin.yaml +66 -0
  390. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/kvlang.yaml +67 -0
  391. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/ledger.yaml +14 -0
  392. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/lfe.yaml +17 -0
  393. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/lilypond.yaml +26 -0
  394. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/lisp.yaml +17 -0
  395. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/log.yaml +92 -0
  396. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/lua.yaml +111 -0
  397. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/mail.yaml +25 -0
  398. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/makefile.yaml +38 -0
  399. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/man.yaml +12 -0
  400. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/markdown.yaml +65 -0
  401. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/mc.yaml +23 -0
  402. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/meson.yaml +51 -0
  403. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/micro.yaml +34 -0
  404. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/mpdconf.yaml +13 -0
  405. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/msbuild.yaml +6 -0
  406. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/nanorc.yaml +16 -0
  407. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/nftables.yaml +30 -0
  408. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/nginx.yaml +22 -0
  409. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/nim.yaml +27 -0
  410. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/nix.yaml +32 -0
  411. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/nu.yaml +114 -0
  412. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/objc.yaml +60 -0
  413. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/ocaml.yaml +43 -0
  414. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/octave.yaml +83 -0
  415. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/odin.yaml +64 -0
  416. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/pascal.yaml +45 -0
  417. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/patch.yaml +14 -0
  418. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/peg.yaml +16 -0
  419. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/perl.yaml +58 -0
  420. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/php.yaml +60 -0
  421. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/pkg-config.yaml +12 -0
  422. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/po.yaml +12 -0
  423. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/pony.yaml +37 -0
  424. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/pov.yaml +21 -0
  425. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/privoxy-action.yaml +14 -0
  426. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/privoxy-config.yaml +10 -0
  427. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/privoxy-filter.yaml +12 -0
  428. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/proto.yaml +40 -0
  429. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/prql.yaml +84 -0
  430. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/puppet.yaml +22 -0
  431. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/python2.yaml +60 -0
  432. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/python3.yaml +80 -0
  433. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/r.yaml +32 -0
  434. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/raku.yaml +42 -0
  435. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/reST.yaml +18 -0
  436. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/renpy.yaml +15 -0
  437. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/rpmspec.yaml +43 -0
  438. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/ruby.yaml +73 -0
  439. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/rust.yaml +78 -0
  440. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/sage.yaml +60 -0
  441. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/scad.yaml +53 -0
  442. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/scala.yaml +33 -0
  443. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/sed.yaml +13 -0
  444. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/sh.yaml +69 -0
  445. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/sls.yaml +15 -0
  446. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/smalltalk.yaml +55 -0
  447. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/solidity.yaml +41 -0
  448. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/sql.yaml +35 -0
  449. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/stata.yaml +67 -0
  450. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/svelte.yaml +27 -0
  451. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/swift.yaml +103 -0
  452. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/systemd.yaml +16 -0
  453. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/tcl.yaml +18 -0
  454. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/terraform.yaml +87 -0
  455. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/tex.yaml +32 -0
  456. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/toml.yaml +56 -0
  457. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/twig.yaml +55 -0
  458. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/typescript.yaml +49 -0
  459. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/v.yaml +80 -0
  460. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/vala.yaml +26 -0
  461. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/verilog.yaml +60 -0
  462. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/vhdl.yaml +37 -0
  463. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/vi.yaml +31 -0
  464. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/vue.yaml +64 -0
  465. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/xml.yaml +37 -0
  466. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/xresources.yaml +14 -0
  467. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/yaml.yaml +34 -0
  468. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/yum.yaml +12 -0
  469. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/zig.yaml +52 -0
  470. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/zscript.yaml +72 -0
  471. package/initramfs/buninu/apps/jsmdcui/runtime/syntax/zsh.yaml +52 -0
  472. package/initramfs/buninu/apps/jsmdcui/single-exe/README.md +396 -0
  473. package/initramfs/buninu/apps/jsmdcui/single-exe/assetsHelper.js +371 -0
  474. package/initramfs/buninu/apps/jsmdcui/single-exe/assetsLoader.mjs +85 -0
  475. package/initramfs/buninu/apps/jsmdcui/single-exe/assetsPacker.js +218 -0
  476. package/initramfs/buninu/apps/jsmdcui/single-exe/compiled.js +498 -0
  477. package/initramfs/buninu/apps/jsmdcui/single-exe/entry.mjs +17 -0
  478. package/initramfs/buninu/apps/jsmdcui/single-exe/packAssets.sh +7 -0
  479. package/initramfs/buninu/apps/jsmdcui/src/MDCUI_DEFAULT_EDIT +0 -0
  480. package/initramfs/buninu/apps/jsmdcui/src/buffer/backup.js +165 -0
  481. package/initramfs/buninu/apps/jsmdcui/src/buffer/buffer.js +126 -0
  482. package/initramfs/buninu/apps/jsmdcui/src/buffer/fixed3-codec.js +140 -0
  483. package/initramfs/buninu/apps/jsmdcui/src/buffer/loc.js +38 -0
  484. package/initramfs/buninu/apps/jsmdcui/src/buffer/message.js +29 -0
  485. package/initramfs/buninu/apps/jsmdcui/src/build-args.js +40 -0
  486. package/initramfs/buninu/apps/jsmdcui/src/config/clean.js +172 -0
  487. package/initramfs/buninu/apps/jsmdcui/src/config/colorscheme.js +99 -0
  488. package/initramfs/buninu/apps/jsmdcui/src/config/config.js +125 -0
  489. package/initramfs/buninu/apps/jsmdcui/src/config/defaults.js +109 -0
  490. package/initramfs/buninu/apps/jsmdcui/src/cui/fence-events.mjs +144 -0
  491. package/initramfs/buninu/apps/jsmdcui/src/cui/heading-ids.mjs +1568 -0
  492. package/initramfs/buninu/apps/jsmdcui/src/cui/id-collision.mjs +111 -0
  493. package/initramfs/buninu/apps/jsmdcui/src/cui/identity.mjs +26 -0
  494. package/initramfs/buninu/apps/jsmdcui/src/cui/kitty-debug.mjs +25 -0
  495. package/initramfs/buninu/apps/jsmdcui/src/cui/kitty-images.mjs +280 -0
  496. package/initramfs/buninu/apps/jsmdcui/src/cui/kitty-mode.mjs +6 -0
  497. package/initramfs/buninu/apps/jsmdcui/src/cui/rerender-queue.mjs +66 -0
  498. package/initramfs/buninu/apps/jsmdcui/src/cui/rpc.mjs +1554 -0
  499. package/initramfs/buninu/apps/jsmdcui/src/cui/server.mjs +128 -0
  500. package/initramfs/buninu/apps/jsmdcui/src/cui/table-render.mjs +286 -0
  501. package/initramfs/buninu/apps/jsmdcui/src/cui/table-row-edit.mjs +226 -0
  502. package/initramfs/buninu/apps/jsmdcui/src/cui/task-checkbox.mjs +60 -0
  503. package/initramfs/buninu/apps/jsmdcui/src/cui/template-components.mjs +253 -0
  504. package/initramfs/buninu/apps/jsmdcui/src/cui/text-block-resize.mjs +177 -0
  505. package/initramfs/buninu/apps/jsmdcui/src/cui/tui-links.mjs +560 -0
  506. package/initramfs/buninu/apps/jsmdcui/src/display/ansi-style.js +60 -0
  507. package/initramfs/buninu/apps/jsmdcui/src/highlight/highlighter.js +243 -0
  508. package/initramfs/buninu/apps/jsmdcui/src/highlight/parser.js +225 -0
  509. package/initramfs/buninu/apps/jsmdcui/src/index.js +9586 -0
  510. package/initramfs/buninu/apps/jsmdcui/src/lua/engine.js +68 -0
  511. package/initramfs/buninu/apps/jsmdcui/src/platform/archive.js +50 -0
  512. package/initramfs/buninu/apps/jsmdcui/src/platform/clipboard.js +278 -0
  513. package/initramfs/buninu/apps/jsmdcui/src/platform/commands.js +221 -0
  514. package/initramfs/buninu/apps/jsmdcui/src/platform/terminal.js +5 -0
  515. package/initramfs/buninu/apps/jsmdcui/src/plugins/js-bridge.js +3377 -0
  516. package/initramfs/buninu/apps/jsmdcui/src/plugins/manager.js +674 -0
  517. package/initramfs/buninu/apps/jsmdcui/src/runtime/encodings.js +10 -0
  518. package/initramfs/buninu/apps/jsmdcui/src/runtime/registry.js +134 -0
  519. package/initramfs/buninu/apps/jsmdcui/src/screen/cell-buffer.js +81 -0
  520. package/initramfs/buninu/apps/jsmdcui/src/screen/events.js +263 -0
  521. package/initramfs/buninu/apps/jsmdcui/src/screen/screen.js +249 -0
  522. package/initramfs/buninu/apps/jsmdcui/src/screen/vt100.js +571 -0
  523. package/initramfs/buninu/apps/jsmdcui/src/shell/shell.js +70 -0
  524. package/initramfs/buninu/apps/jsmdcui/testapp.md +78 -0
  525. package/initramfs/buninu/apps/jsmdcui/tests/assets-helper.test.js +150 -0
  526. package/initramfs/buninu/apps/jsmdcui/tests/backup.test.js +158 -0
  527. package/initramfs/buninu/apps/jsmdcui/tests/cat-markdown.test.js +139 -0
  528. package/initramfs/buninu/apps/jsmdcui/tests/cdp-security.test.js +32 -0
  529. package/initramfs/buninu/apps/jsmdcui/tests/cdp-websocket-test.html +46 -0
  530. package/initramfs/buninu/apps/jsmdcui/tests/cmphex3b64.js +95 -0
  531. package/initramfs/buninu/apps/jsmdcui/tests/compiled-runtime.test.js +139 -0
  532. package/initramfs/buninu/apps/jsmdcui/tests/config-settings.test.js +52 -0
  533. package/initramfs/buninu/apps/jsmdcui/tests/demo.test.js +448 -0
  534. package/initramfs/buninu/apps/jsmdcui/tests/docs-sync.test.js +14 -0
  535. package/initramfs/buninu/apps/jsmdcui/tests/fence-events.test.js +1293 -0
  536. package/initramfs/buninu/apps/jsmdcui/tests/heading-ids.test.js +559 -0
  537. package/initramfs/buninu/apps/jsmdcui/tests/heading-list-selector.test.js +2393 -0
  538. package/initramfs/buninu/apps/jsmdcui/tests/id-collision.test.js +514 -0
  539. package/initramfs/buninu/apps/jsmdcui/tests/jmigt.js +16 -0
  540. package/initramfs/buninu/apps/jsmdcui/tests/js-plugin-prompts.test.js +110 -0
  541. package/initramfs/buninu/apps/jsmdcui/tests/key-event.md +10 -0
  542. package/initramfs/buninu/apps/jsmdcui/tests/kitty-demo.md +184 -0
  543. package/initramfs/buninu/apps/jsmdcui/tests/kitty-images.test.js +288 -0
  544. package/initramfs/buninu/apps/jsmdcui/tests/kitty-mode.test.js +14 -0
  545. package/initramfs/buninu/apps/jsmdcui/tests/platform-commands.test.js +18 -0
  546. package/initramfs/buninu/apps/jsmdcui/tests/platform-terminal.test.js +8 -0
  547. package/initramfs/buninu/apps/jsmdcui/tests/pty-demo.js +492 -0
  548. package/initramfs/buninu/apps/jsmdcui/tests/rerender-queue.test.js +130 -0
  549. package/initramfs/buninu/apps/jsmdcui/tests/table-render.test.js +150 -0
  550. package/initramfs/buninu/apps/jsmdcui/tests/table-row-edit.test.js +138 -0
  551. package/initramfs/buninu/apps/jsmdcui/tests/task-checkbox.test.js +33 -0
  552. package/initramfs/buninu/apps/jsmdcui/tests/template-components.test.js +422 -0
  553. package/initramfs/buninu/apps/jsmdcui/tests/text-block-resize.test.js +222 -0
  554. package/initramfs/buninu/apps/jsmdcui/tests/textarea.md +8 -0
  555. package/initramfs/buninu/apps/jsmdcui/tests/tui-links.test.js +298 -0
  556. package/initramfs/buninu/apps/jsmdcui/tests/wui-responsive-images.test.js +60 -0
  557. package/initramfs/buninu/apps/jsmdcui/tests/wui.test.js +108 -0
  558. package/initramfs/buninu/apps/jsmdcui/tests/wv-client.js +96 -0
  559. package/initramfs/buninu/apps/jsmdcui/tui +7 -0
  560. package/initramfs/buninu/apps/jsmdcui/wui +9 -0
  561. package/initramfs/buninu/apps/musl-la/LICENSES/GPL-3.0.txt +674 -0
  562. package/initramfs/buninu/apps/musl-la/LICENSES/gcc_runtime_exception.txt +73 -0
  563. package/initramfs/buninu/apps/musl-la/LICENSE_musl.txt +193 -0
  564. package/initramfs/buninu/apps/musl-la/NOTICE +41 -0
  565. package/initramfs/buninu/apps/musl-la/ld-musl-aarch64.so.1 +0 -0
  566. package/initramfs/buninu/apps/musl-la/libgcc_s.so.1 +0 -0
  567. package/initramfs/buninu/apps/musl-la/libstdc++.so.6 +0 -0
  568. package/initramfs/buninu/apps/musl-la/musl-la.sh +36 -0
  569. package/initramfs/buninu/apps/native-bridge/native-bridge.js +199 -0
  570. package/initramfs/buninu/apps/native-bridge/package.json +8 -0
  571. package/initramfs/buninu/apps/tts/tts.js +214 -0
  572. package/initramfs/buninu/apps/xclip/xclip.js +121 -0
  573. package/initramfs/buninu/apps/xdg-open/xdg-open.js +151 -0
  574. package/initramfs/buninu/bin/bun.bat +37 -0
  575. package/initramfs/buninu/bin/bun.sh +57 -0
  576. package/initramfs/buninu/bin/buninu-help.bat +4 -0
  577. package/initramfs/buninu/bin/buninu-help.sh +7 -0
  578. package/initramfs/buninu/bin/bunmsh.bat +3 -0
  579. package/initramfs/buninu/bin/bunmsh.sh +5 -0
  580. package/initramfs/buninu/bin/bunx.bat +3 -0
  581. package/initramfs/buninu/bin/glow.bat +3 -0
  582. package/initramfs/buninu/bin/glow.sh +5 -0
  583. package/initramfs/buninu/bin/init.js +779 -0
  584. package/initramfs/buninu/bin/install.js +570 -0
  585. package/initramfs/buninu/bin/jmi.bat +3 -0
  586. package/initramfs/buninu/bin/jmi.sh +5 -0
  587. package/initramfs/buninu/bin/jsgotty.bat +3 -0
  588. package/initramfs/buninu/bin/jsgotty.sh +5 -0
  589. package/initramfs/buninu/bin/jsmdcui.bat +11 -0
  590. package/initramfs/buninu/bin/libsh-loader.c +135 -0
  591. package/initramfs/buninu/bin/libsh-loader.so +0 -0
  592. package/initramfs/buninu/bin/multicall.sh +103 -0
  593. package/initramfs/buninu/bin/native-bridge.bat +3 -0
  594. package/initramfs/buninu/bin/rz.bat +3 -0
  595. package/initramfs/buninu/bin/rz.sh +5 -0
  596. package/initramfs/buninu/bin/shc.js +5 -0
  597. package/initramfs/buninu/bin/showimg.bat +3 -0
  598. package/initramfs/buninu/bin/showimg.sh +5 -0
  599. package/initramfs/buninu/bin/switch_to_android.sh +9 -0
  600. package/initramfs/buninu/bin/switch_to_linux.sh +7 -0
  601. package/initramfs/buninu/bin/sz.bat +3 -0
  602. package/initramfs/buninu/bin/sz.sh +5 -0
  603. package/initramfs/buninu/bin/tts.bat +3 -0
  604. package/initramfs/buninu/bin/xclip.bat +3 -0
  605. package/initramfs/buninu/bin/xdg-open.bat +3 -0
  606. package/initramfs/buninu/demo-server.js +64 -0
  607. package/initramfs/buninu/icon.png +0 -0
  608. package/initramfs/buninu/package.json +59 -0
  609. package/initramfs/etc/resolv.conf +1 -0
  610. package/initramfs/init.js +339 -0
  611. package/initramfs/lib/ld-musl-x86_64.so.1 +0 -0
  612. package/initramfs/lib/libc.musl-x86_64.so.1 +0 -0
  613. package/initramfs/lib/libgcc_s.so.1 +0 -0
  614. package/initramfs/lib/libstdc++.so.6 +0 -0
  615. package/initramfs/usr/bin/env +7 -0
  616. package/package.json +42 -0
  617. package/run-qemu.sh +44 -0
  618. package/scripts/fetch.sh +26 -0
  619. package/scripts/pack-initramfs.sh +41 -0
  620. package/test/build-init-bootstrap.sh +23 -0
  621. package/test/init-bootstrap.c +55 -0
@@ -0,0 +1,1087 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { chmodSync, mkdirSync, mkdtempSync, readlinkSync, rmSync, statSync, symlinkSync, utimesSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import {
6
+ bunShellFallbackArgv,
7
+ builtinNames,
8
+ createState,
9
+ decode,
10
+ execute,
11
+ colorProcessCommand,
12
+ colorProcessTable,
13
+ highlightShellCommand,
14
+ executeArgv,
15
+ formatProcessTable,
16
+ isJavaScriptMode,
17
+ needsMoreInput,
18
+ parse,
19
+ parsePosixProcessList,
20
+ parseWindowsProcessList,
21
+ runUnameFallback,
22
+ SH_COLORS,
23
+ taskkillFailure,
24
+ tokenize,
25
+ windowsKillCommand,
26
+ } from "../src/shell.js";
27
+ import {
28
+ CommandIndex,
29
+ FileIndex,
30
+ VariableIndex,
31
+ completionContext,
32
+ fitGhost,
33
+ firstPrefixMatch,
34
+ historyGhost,
35
+ javascriptContext,
36
+ nextGhostChunk,
37
+ prefixMatches,
38
+ variableCompletion,
39
+ variableContext,
40
+ } from "../src/completion.js";
41
+ import {
42
+ bunmshHistoryPath,
43
+ importedHistory,
44
+ parseBashHistory,
45
+ parseFishHistory,
46
+ readlineHistory,
47
+ saveBunmshHistory,
48
+ safeHistoryEntry,
49
+ } from "../src/history.js";
50
+ import { isLinkerPath } from "../single-exe/compiled.js";
51
+ import { readAssetText } from "../single-exe/assetsHelper.js";
52
+ import { fancyLs } from "../src/fancy-ls.js";
53
+ import { MOUSE_OFF, MOUSE_ON, mouseInput } from "../src/mouse.js";
54
+ import { canonicalEnvironment, environmentValue, homeRelativePath } from "../src/environment.js";
55
+ import { findIsRegularBuiltin } from "../src/find.js";
56
+
57
+ async function run(source, options = {}) {
58
+ const state = createState({
59
+ env: { HOME: "/tmp", ...options.env },
60
+ cwd: options.cwd ?? process.cwd(),
61
+ args: options.args ?? ["bunmsh"],
62
+ history: options.history ?? [],
63
+ mouseTracking: options.mouseTracking,
64
+ pathSearch: options.pathSearch,
65
+ });
66
+ const output = await execute(source, state, { capture: true });
67
+ return {
68
+ ...output,
69
+ stdout: decode(output.stdout),
70
+ stderr: decode(output.stderr),
71
+ state,
72
+ };
73
+ }
74
+
75
+ describe("parser", () => {
76
+ test("recognizes supported ELF and Android dynamic linker names", () => {
77
+ expect(isLinkerPath("/lib/ld-linux-aarch64.so.1")).toBe(true);
78
+ expect(isLinkerPath("/lib/ld-musl-x86_64.so.1")).toBe(true);
79
+ expect(isLinkerPath("/system/bin/linker64")).toBe(true);
80
+ expect(isLinkerPath("/system/bin/linker")).toBe(true);
81
+ expect(isLinkerPath("/usr/bin/ld")).toBe(false);
82
+ expect(isLinkerPath("/usr/bin/bun")).toBe(false);
83
+ });
84
+
85
+ test("tokenizes quotes and operators", () => {
86
+ const tokens = tokenize(`echo "a b" | cat && print ok`);
87
+ expect(tokens.filter((token) => token.type === "op").map((token) => token.value))
88
+ .toEqual(["|", "&&"]);
89
+ });
90
+
91
+ test("parses a pipeline", () => {
92
+ expect(parse("echo hi | tr a-z A-Z")[0].pipeline).toHaveLength(2);
93
+ });
94
+
95
+ test("a bare trailing backslash asks for one more interactive line, then joins", () => {
96
+ // This is what the interactive prompt loop's `pending` string looks like
97
+ // the instant Enter is pressed after typing "echo hi \" -- the next
98
+ // physical line hasn't arrived yet, so there's no following "\n" for the
99
+ // ordinary backslash-newline splice to recognize.
100
+ expect(needsMoreInput("echo hi \\")).toBe(true);
101
+ expect(() => tokenize("echo hi \\", { strict: true }))
102
+ .toThrow("unterminated line continuation");
103
+ // Once the next line lands, `pending` gains the "\n" and the pair joins
104
+ // into one already-complete command -- no more waiting.
105
+ expect(needsMoreInput("echo hi \\\nbye")).toBe(false);
106
+ expect(tokenize("echo hi \\\nbye").map((token) => token.fragments?.[0]?.text))
107
+ .toEqual(["echo", "hi", "bye"]);
108
+ });
109
+
110
+ test("non-strict tokenize keeps accepting a trailing backslash as a literal word", () => {
111
+ // Only needsMoreInput's strict parse should wait for more input; a
112
+ // script or -c string whose last line genuinely ends in "\" at EOF keeps
113
+ // parsing the same way it always has.
114
+ const tokens = tokenize("echo hi \\");
115
+ expect(tokens.at(-1).fragments).toEqual([{ text: "\\", quote: "none" }]);
116
+ });
117
+ });
118
+
119
+ describe("completion", () => {
120
+ test("treats Windows Path as PATH after copying process.env", () => {
121
+ const env = canonicalEnvironment({
122
+ TEMP: "C:\\Temp",
123
+ Path: "C:\\Windows;C:\\Tools",
124
+ UserProfile: "C:\\Users\\me",
125
+ }, "win32");
126
+ expect(env.PATH).toBe("C:\\Windows;C:\\Tools");
127
+ expect(env.Path).toBeUndefined();
128
+ expect(env.HOME).toBe("C:/Users/me");
129
+ expect(environmentValue({ path: "C:\\Bin" }, "PATH", "win32")).toBe("C:\\Bin");
130
+ expect(canonicalEnvironment({
131
+ HOME: "D:\\ShellHome",
132
+ USERPROFILE: "C:\\Users\\ignored",
133
+ }, "win32").HOME).toBe("D:/ShellHome");
134
+ expect(canonicalEnvironment({
135
+ HOMEDRIVE: "C:",
136
+ HOMEPATH: "\\Users\\fallback",
137
+ }, "win32").HOME).toBe("C:/Users/fallback");
138
+ expect(findIsRegularBuiltin("win32")).toBe(true);
139
+ expect(findIsRegularBuiltin("linux")).toBe(false);
140
+ });
141
+
142
+ test("recognizes Android app-data aliases and Windows case in HOME-relative paths", () => {
143
+ expect(homeRelativePath(
144
+ "/data/user/0/com.termux/files/home",
145
+ "/data/data/com.termux/files/home",
146
+ )).toBe("");
147
+ expect(homeRelativePath(
148
+ "/data/data/com.termux/files/home/project",
149
+ "/data/user/0/com.termux/files/home",
150
+ )).toBe("/project");
151
+ expect(homeRelativePath(
152
+ "c:/users/name/project",
153
+ "C:\\Users\\Name",
154
+ "win32",
155
+ )).toBe("/project");
156
+ expect(homeRelativePath("/elsewhere", "/home/name")).toBeNull();
157
+ });
158
+
159
+ test("removes split SGR mouse and cursor reports from readline input", async () => {
160
+ const mice = [];
161
+ const cursors = [];
162
+ const shortcuts = [];
163
+ let forwarded = "";
164
+ const input = mouseInput(
165
+ (event) => mice.push(event),
166
+ (position) => cursors.push(position),
167
+ (shortcut) => shortcuts.push(shortcut),
168
+ );
169
+ input.on("data", (chunk) => { forwarded += chunk.toString(); });
170
+ input.write("echo ");
171
+ input.write("\x1b[<0;12");
172
+ input.write(";3M\x1b[4;9Rok\x14\x1bt\x1bl\x1bu\x1bp\x1bc");
173
+ input.end();
174
+ await new Promise((resolve) => input.once("end", resolve));
175
+ expect(forwarded).toBe("echo ok");
176
+ expect(mice).toEqual([{ button: 0, x: 12, y: 3, press: true }]);
177
+ expect(cursors).toEqual([{ row: 4, column: 9 }]);
178
+ expect(shortcuts).toEqual([
179
+ "tab", "tab-left", "lsfancy", "lsfancy-parent", "lsfancy-parent",
180
+ "tab-close",
181
+ ]);
182
+ });
183
+
184
+ test("imports Bash and Fish history by default and can be disabled", async () => {
185
+ expect(parseBashHistory("#1720000000\necho bash\n\nshared\n"))
186
+ .toEqual(["echo bash", "shared"]);
187
+ expect(parseFishHistory("- cmd: echo fish\n when: 1720000001\n- cmd: shared\n"))
188
+ .toEqual(["echo fish", "shared"]);
189
+ expect(parseFishHistory("- cmd: echo invalid YAML: value\n when: 1720000002\n- cmd: cp Hello2.apk /sdcard/Documents/\n"))
190
+ .toEqual(["echo invalid YAML: value", "cp Hello2.apk /sdcard/Documents/"]);
191
+
192
+ const home = mkdtempSync(join(tmpdir(), "bunmsh-history-"));
193
+ try {
194
+ mkdirSync(join(home, ".local", "share", "fish"), { recursive: true });
195
+ await Bun.write(join(home, ".bash_history"), "echo bash\nshared\n");
196
+ await Bun.write(join(home, ".local", "share", "fish", "fish_history"),
197
+ "- cmd: echo fish\n when: 1720000001\n- cmd: shared\n");
198
+ expect(await importedHistory({ HOME: home }))
199
+ .toEqual(["echo bash", "echo fish", "shared"]);
200
+ expect(await importedHistory({ HOME: home, BUNMSH_IMPORT_HISTORY: "off" })).toEqual([]);
201
+ } finally { rmSync(home, { recursive: true, force: true }); }
202
+ });
203
+
204
+ test("rejects terminal controls from every history source and ghost lookup", () => {
205
+ const dangerous = "cp file\x1b[2D";
206
+ expect(safeHistoryEntry(dangerous)).toBe(false);
207
+ expect(safeHistoryEntry("cp file\nrm file")).toBe(false);
208
+ expect(parseBashHistory(`cp safe\n${dangerous}\n`)).toEqual(["cp safe"]);
209
+ expect(parseFishHistory(`- cmd: cp safe\n- cmd: ${dangerous}\n`))
210
+ .toEqual(["cp safe"]);
211
+ expect(historyGhost([dangerous, "cp safe-file"], "cp ")).toBe("safe-file");
212
+ expect(historyGhost([dangerous], "cp ")).toBeNull();
213
+ });
214
+
215
+ test("feeds saved history to readline in newest-first order", () => {
216
+ expect(readlineHistory(["echo first", "ls", "pwd"]))
217
+ .toEqual(["pwd", "ls", "echo first"]);
218
+ expect(readlineHistory(["safe", "bad\x1b[2D"]))
219
+ .toEqual(["safe"]);
220
+ });
221
+
222
+ test("uses platform-standard bunmsh history paths", () => {
223
+ expect(bunmshHistoryPath({ HOME: "/home/user" }, "linux"))
224
+ .toBe("/home/user/.local/share/bunmsh/history");
225
+ expect(bunmshHistoryPath({ HOME: "/home/user", XDG_DATA_HOME: "/data" }, "linux"))
226
+ .toBe("/data/bunmsh/history");
227
+ expect(bunmshHistoryPath({ LOCALAPPDATA: "C:\\Users\\me\\AppData\\Local" }, "win32"))
228
+ .toBe("C:\\Users\\me\\AppData\\Local/bunmsh/history");
229
+ });
230
+
231
+ test("finds prefix ranges in a sorted command index", () => {
232
+ const names = ["bun", "bunx", "cat", "git"];
233
+ expect(prefixMatches(names, "bu")).toEqual(["bun", "bunx"]);
234
+ expect(firstPrefixMatch(names, "gi")).toBe("git");
235
+ expect(prefixMatches(names, "")).toEqual([]);
236
+ });
237
+
238
+ test("recognizes command positions after assignments and operators", () => {
239
+ expect(completionContext("bu")).toMatchObject({ command: true, prefix: "bu" });
240
+ expect(completionContext("X=1 bu")).toMatchObject({ command: true, prefix: "bu" });
241
+ expect(completionContext("echo hi | gr")).toMatchObject({ command: true, prefix: "gr" });
242
+ expect(completionContext("echo bu")).toMatchObject({ command: false, prefix: "bu" });
243
+ expect(completionContext("echo ")).toMatchObject({ command: false, prefix: "" });
244
+ });
245
+
246
+ test("uses recent history for ghosts and accepts one word at a time", () => {
247
+ const history = ["git status", "git log --oneline", "git status --short"];
248
+ expect(historyGhost(history, "git status")).toBe(" --short");
249
+ expect(nextGhostChunk(" --short branch")).toBe(" --short ");
250
+ expect(nextGhostChunk("branch")).toBe("branch");
251
+ });
252
+
253
+ test("clips long ghosts before they wrap and disturb the cursor", () => {
254
+ const ghost = "src/proot packed/proot; PROOT_PORT_ADD=3000 bun packed/srpr.mjs";
255
+ expect(fitGhost(ghost, 20)).toEqual({ output: "src/proot packed/pro", width: 20 });
256
+ expect(fitGhost(ghost, 0)).toEqual({ output: "", width: 0 });
257
+ expect(fitGhost("檔案-name", 5)).toEqual({ output: "檔案-", width: 5 });
258
+ });
259
+
260
+ test("indexes PATH names without checking executable permission", async () => {
261
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-completion-"));
262
+ try {
263
+ await Bun.write(`${directory}/alpha`, "not executable");
264
+ await Bun.write(`${directory}/alpine`, "also not executable");
265
+ const index = new CommandIndex(["alias"]);
266
+ await index.refresh({ cwd: process.cwd(), env: { PATH: directory }, aliases: {} });
267
+ expect(index.matches("al")).toEqual(["alias", "alpha", "alpine"]);
268
+ } finally {
269
+ rmSync(directory, { recursive: true, force: true });
270
+ }
271
+ });
272
+
273
+ test("uses the platform PATH delimiter and hides Windows executable extensions", async () => {
274
+ const first = mkdtempSync(join(tmpdir(), "bunmsh-win-path-a-"));
275
+ const second = mkdtempSync(join(tmpdir(), "bunmsh-win-path-b-"));
276
+ try {
277
+ await Bun.write(`${first}/Alpha.EXE`, "exe");
278
+ await Bun.write(`${first}/ignored.txt`, "text");
279
+ await Bun.write(`${second}/beta.cmd`, "cmd");
280
+ await Bun.write(`${second}/gamma.bat`, "bat");
281
+ const index = new CommandIndex([], { platform: "win32", pathDelimiter: ";" });
282
+ await index.refresh({
283
+ cwd: process.cwd(),
284
+ env: { PATH: `${first};${second}` },
285
+ aliases: {},
286
+ });
287
+ expect(index.matches("A")).toEqual(["Alpha"]);
288
+ expect(index.matches("b")).toEqual(["beta"]);
289
+ expect(index.matches("g")).toEqual(["gamma"]);
290
+ expect(index.matches("i")).toEqual([]);
291
+ } finally {
292
+ rmSync(first, { recursive: true, force: true });
293
+ rmSync(second, { recursive: true, force: true });
294
+ }
295
+ });
296
+
297
+ test("suggests files and marks directories with a trailing slash", async () => {
298
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-files-"));
299
+ try {
300
+ await Bun.write(`${directory}/alpha.txt`, "alpha");
301
+ mkdirSync(`${directory}/alpine`);
302
+ const index = new FileIndex();
303
+ const state = { cwd: directory, env: {} };
304
+ expect(index.matches("", state)).toEqual(["alpha.txt", "alpine/"]);
305
+ expect(index.matches("al", state)).toEqual(["alpha.txt", "alpine/"]);
306
+ expect(index.first("alpha", state)).toBe("alpha.txt");
307
+ } finally {
308
+ rmSync(directory, { recursive: true, force: true });
309
+ }
310
+ });
311
+ });
312
+
313
+ describe("execution", () => {
314
+ test("normalizes Bun Shell cp recursion and provides a PATH-independent cat", async () => {
315
+ expect(bunShellFallbackArgv(["cp", "-rv", "a", "b"]))
316
+ .toEqual(["cp", "-Rv", "a", "b"]);
317
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-cat-"));
318
+ try {
319
+ await Bun.write(`${directory}/a.txt`, "alpha");
320
+ await Bun.write(`${directory}/b.txt`, "beta");
321
+ const output = await run("cat a.txt b.txt", {
322
+ cwd: directory,
323
+ env: { PATH: "/no/such/path" },
324
+ });
325
+ expect(output).toMatchObject({ status: 0, stdout: "alphabeta", stderr: "" });
326
+ const excluded = await run("builtin cat --exclude a.txt *.txt", { cwd: directory });
327
+ expect(excluded).toMatchObject({ status: 0, stdout: "beta", stderr: "" });
328
+ const patternExcluded = await run("builtin cat --exclude 'a.*' *.txt", { cwd: directory });
329
+ expect(patternExcluded).toMatchObject({ status: 0, stdout: "beta", stderr: "" });
330
+ mkdirSync(`${directory}/source`);
331
+ await Bun.write(`${directory}/source/item.txt`, "copied");
332
+ const copied = await run("cp -r source target", {
333
+ cwd: directory,
334
+ env: { PATH: "/no/such/path" },
335
+ });
336
+ expect(copied).toMatchObject({ status: 0, stdout: "", stderr: "" });
337
+ expect(await Bun.file(`${directory}/target/item.txt`).text()).toBe("copied");
338
+ } finally {
339
+ rmSync(directory, { recursive: true, force: true });
340
+ }
341
+ });
342
+
343
+ test("normalizes CRLF source before parsing scripts", async () => {
344
+ const compound = [
345
+ 'value="two words"',
346
+ 'if [ "$value" = "two words" ]; then',
347
+ " printf '[%s]\\n' \"$value\"",
348
+ "fi",
349
+ "",
350
+ ].join("\r\n");
351
+ expect(await run(compound)).toMatchObject({
352
+ status: 0,
353
+ stdout: "[two words]\n",
354
+ stderr: "",
355
+ });
356
+
357
+ const heredoc = [
358
+ "builtin cat <<'EOF'",
359
+ "$value remains literal",
360
+ "EOF",
361
+ "",
362
+ ].join("\r\n");
363
+ expect(await run(heredoc)).toMatchObject({
364
+ status: 0,
365
+ stdout: "$value remains literal\n",
366
+ stderr: "",
367
+ });
368
+ });
369
+
370
+ test("provides basic fallback text and utility commands", async () => {
371
+ expect(await run("printf 'c\\na\\nb\\n' | builtin sort")).toMatchObject({ stdout: "a\nb\nc\n" });
372
+ expect(await run("printf 'one two\\nthree\\n' | builtin wc -lwc")).toMatchObject({ stdout: "2 3 14\n" });
373
+ expect(await run("printf 'abc\\n' | builtin tr a-z A-Z")).toMatchObject({ stdout: "ABC\n" });
374
+ expect(await run("printf '1\\n2\\n3\\n' | builtin head -n 2")).toMatchObject({ stdout: "1\n2\n" });
375
+ expect(await run("printf '1\\n2\\n3\\n' | builtin tail -n 2")).toMatchObject({ stdout: "2\n3\n" });
376
+ expect(await run("printf '1\\n2\\n3\\n' | builtin tail -n +2")).toMatchObject({ stdout: "2\n3\n" });
377
+ expect(await run("printf '1\\n2\\n3\\n' | builtin tail -n+3")).toMatchObject({ stdout: "3\n" });
378
+ expect(await run("printf '1\\n2\\n3\\n' | builtin tac")).toMatchObject({ stdout: "3\n2\n1\n" });
379
+ expect(await run("printf '1\\n2' | builtin tac")).toMatchObject({ stdout: "21\n" });
380
+ expect(await run("builtin date +%F")).toMatchObject({ status: 0 });
381
+ expect(await run("builtin sleep 1ms")).toMatchObject({ status: 0, stdout: "", stderr: "" });
382
+ });
383
+
384
+ test("tr translates and deletes NUL bytes", async () => {
385
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-tr-"));
386
+ const cmdline = join(directory, "cmdline");
387
+ try {
388
+ await Bun.write(cmdline, new Uint8Array([
389
+ ...new TextEncoder().encode("/buninu/bin/jmi"), 0,
390
+ ...new TextEncoder().encode("hlw.js"), 0,
391
+ ]));
392
+ expect(await run(`builtin tr '\\0' '\\n' < '${cmdline}'`)).toMatchObject({
393
+ status: 0,
394
+ stdout: "/buninu/bin/jmi\nhlw.js\n",
395
+ stderr: "",
396
+ });
397
+ expect(await run(`builtin tr -d '\\000' < '${cmdline}'`)).toMatchObject({
398
+ status: 0,
399
+ stdout: "/buninu/bin/jmihlw.js",
400
+ stderr: "",
401
+ });
402
+ } finally {
403
+ rmSync(directory, { recursive: true, force: true });
404
+ }
405
+ });
406
+
407
+ test("renders asset-backed Markdown help for every documented builtin", async () => {
408
+ const excluded = new Set([".", "..", "//", "-", "~"]);
409
+ const titles = { "[": "test", __builtin: "builtin", chdir: "cd" };
410
+ const files = { ":": "colon", ...titles };
411
+ const optionDocs = new Set([
412
+ "basename", "builtin", "bun", "bunmsh", "cat", "catfancy", "chmod", "command", "cp", "cut",
413
+ "curl", "date", "dirname", "echo", "env", "find", "getopts", "grep", "head", "kill",
414
+ "ln", "ls", "lsbun", "lsfancy", "mkdir", "mktemp", "mv", "print", "printf",
415
+ "read", "readonly", "rm", "rmdir", "sed", "seq", "serve", "set", "sleep",
416
+ "sort", "tab", "tac", "tail", "tee", "test", "touch", "tr", "unalias",
417
+ "uname", "unset", "wc", "whence",
418
+ ]);
419
+ const state = createState({ env: { HOME: "/tmp", PATH: "/no/such/path" } });
420
+ for (const name of builtinNames().filter((item) => !excluded.has(item))) {
421
+ const output = await executeArgv(["builtin", name, "--help"], state, { capture: true });
422
+ expect(output.status, name).toBe(0);
423
+ const text = decode(output.stdout);
424
+ expect(text, name).toContain("\x1b[");
425
+ expect(Bun.stripANSI(text), name).toStartWith(titles[name] ?? name);
426
+ const source = await readAssetText(`help/${files[name] ?? name}.md`);
427
+ expect(source, name).toStartWith(`## ${titles[name] ?? name}`);
428
+ expect(source, name).toContain("\n### Example\n");
429
+ expect(source, name).toContain("\n```sh\n");
430
+ expect(source, name).toContain("\nOutput:\n\n```text\n");
431
+ if (optionDocs.has(files[name] ?? name))
432
+ expect(source, name).toMatch(/^### Options(?: and forms)?$/m);
433
+ }
434
+
435
+ const short = await executeArgv(["builtin", "catfancy", "-h"], state, { capture: true });
436
+ expect(short.status).toBe(0);
437
+ expect(Bun.stripANSI(decode(short.stdout))).toStartWith("catfancy");
438
+
439
+ const lsfancyShort = await executeArgv(
440
+ ["builtin", "lsfancy", "-h"],
441
+ createState({ cwd: new URL("..", import.meta.url).pathname }),
442
+ { capture: true },
443
+ );
444
+ expect(lsfancyShort.status).toBe(0);
445
+ expect(Bun.stripANSI(decode(lsfancyShort.stdout))).toContain("README.md");
446
+ expect(Bun.stripANSI(decode(lsfancyShort.stdout))).not.toContain("Usage");
447
+
448
+ const lsfancyHelp = await executeArgv(
449
+ ["builtin", "lsfancy", "--help"], state, { capture: true },
450
+ );
451
+ expect(lsfancyHelp.status).toBe(0);
452
+ expect(Bun.stripANSI(decode(lsfancyHelp.stdout))).toStartWith("lsfancy");
453
+
454
+ const basenameHelp = await readAssetText("help/basename.md");
455
+ expect(basenameHelp).toContain("basename archive.tar.gz .gz");
456
+ expect(basenameHelp).toContain("archive.tar");
457
+ });
458
+
459
+ test("catfancy is a PATH-overridable fallback builtin", async () => {
460
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-catfancy-path-"));
461
+ try {
462
+ await Bun.write(join(directory, "data.json5"), "{answer: 42}");
463
+ const fallback = await run("catfancy data.json5", {
464
+ cwd: directory,
465
+ env: { PATH: "/no/such/path" },
466
+ });
467
+ expect(fallback.status).toBe(0);
468
+ expect(Bun.stripANSI(fallback.stdout)).toBe('{\n "answer": 42\n}\n');
469
+
470
+ const executable = join(directory, "catfancy");
471
+ await Bun.write(executable, "#!/bin/sh\necho external-catfancy\n");
472
+ chmodSync(executable, 0o755);
473
+ const external = await run("catfancy data.json5; builtin catfancy data.json5", {
474
+ cwd: directory,
475
+ env: { PATH: directory },
476
+ });
477
+ expect(external.status).toBe(0);
478
+ expect(external.stdout).toStartWith("external-catfancy\n");
479
+ expect(Bun.stripANSI(external.stdout)).toContain('"answer": 42');
480
+ } finally {
481
+ rmSync(directory, { recursive: true, force: true });
482
+ }
483
+ });
484
+
485
+ test("lsfancy classifies files by extension and always reads the directory", async () => {
486
+ const cwd = mkdtempSync(join(tmpdir(), "bunmsh-lsfancy-"));
487
+ try {
488
+ mkdirSync(join(cwd, "package"));
489
+ await Bun.write(join(cwd, "photo.png"), "image");
490
+ await Bun.write(join(cwd, "song.mp3"), "music");
491
+ await Bun.write(join(cwd, "app.mjs"), "js");
492
+ await Bun.write(join(cwd, "types.mts"), "ts");
493
+ await Bun.write(join(cwd, "page.html"), "html");
494
+ await Bun.write(join(cwd, "style.css"), "css");
495
+ const first = await run("builtin lsfancy", { cwd });
496
+ expect(first.status).toBe(0);
497
+ expect(first.stdout).toContain("📦 package/");
498
+ expect(first.stdout).toContain("🖼️ photo.png");
499
+ expect(first.stdout).toContain("🎵 song.mp3");
500
+ expect(first.stdout).toContain("🟨 app.mjs");
501
+ expect(first.stdout).toContain("🟦 types.mts");
502
+ expect(first.stdout).toContain("🌐 page.html");
503
+ expect(first.stdout).toContain("🎨 style.css");
504
+ await Bun.write(join(cwd, "new.py"), "pass\n");
505
+ expect((await run("builtin lsfancy", { cwd })).stdout).toContain("🐍 new.py");
506
+ await Bun.write(join(cwd, "large.bin"), "x".repeat(1536));
507
+ const long = await run("builtin lsfancy -lh large.bin", { cwd });
508
+ expect(long.status).toBe(0);
509
+ expect(long.stdout).toContain("1.5K");
510
+ expect(long.stdout).toContain("📄 large.bin");
511
+ await Bun.write(join(cwd, "time-old.txt"), "old");
512
+ await Bun.write(join(cwd, "time-new.txt"), "new");
513
+ utimesSync(join(cwd, "time-old.txt"), new Date(1000), new Date(1000));
514
+ utimesSync(join(cwd, "time-new.txt"), new Date(2000), new Date(2000));
515
+ const timed = await run("builtin lsfancy -ltr", { cwd });
516
+ expect(timed.status).toBe(0);
517
+ expect(timed.stdout.indexOf("time-old.txt"))
518
+ .toBeLessThan(timed.stdout.indexOf("time-new.txt"));
519
+ } finally { rmSync(cwd, { recursive: true, force: true }); }
520
+ });
521
+
522
+ test("lsfancy supports -S (sort by size), -1 (one per line), and -F (classify)", async () => {
523
+ const cwd = mkdtempSync(join(tmpdir(), "bunmsh-lsfancy-flags-"));
524
+ try {
525
+ await Bun.write(join(cwd, "small.txt"), "x");
526
+ await Bun.write(join(cwd, "big.txt"), "x".repeat(100));
527
+ await Bun.write(join(cwd, "script.sh"), "#!/bin/sh\n");
528
+ chmodSync(join(cwd, "script.sh"), 0o755);
529
+ mkdirSync(join(cwd, "subdir"));
530
+ symlinkSync("small.txt", join(cwd, "link_ok"));
531
+
532
+ const bySize = await run("builtin lsfancy -S", { cwd });
533
+ expect(bySize.status).toBe(0);
534
+ expect(bySize.stdout.indexOf("big.txt")).toBeLessThan(bySize.stdout.indexOf("small.txt"));
535
+
536
+ const classified = await run("builtin lsfancy -F", { cwd });
537
+ expect(classified.status).toBe(0);
538
+ expect(classified.stdout).toContain("subdir/");
539
+ expect(classified.stdout).toContain("script.sh*");
540
+ expect(classified.stdout).toContain("link_ok@");
541
+ // A plain regular file gets no classify suffix at all.
542
+ expect(classified.stdout).toContain("small.txt");
543
+ expect(classified.stdout).not.toMatch(/small\.txt[*/@=|]/);
544
+
545
+ // -1 only differs from the default in a terminal (execute()'s non-tty
546
+ // capture path is already one entry per line either way), so exercise
547
+ // fancyLs directly with terminal forced on to see the effect.
548
+ const state = createState({ cwd });
549
+ const wide = fancyLs(["lsfancy"], state, true);
550
+ const single = fancyLs(["lsfancy", "-1"], state, true);
551
+ expect(wide.stdout.split("\n").filter(Boolean).length).toBeLessThan(5);
552
+ expect(single.stdout.split("\n").filter(Boolean).length).toBe(5);
553
+ } finally { rmSync(cwd, { recursive: true, force: true }); }
554
+ });
555
+
556
+ test("lsfancy -l shows a file's mtime in local time, not UTC", async () => {
557
+ const cwd = mkdtempSync(join(tmpdir(), "bunmsh-lsfancy-localtime-"));
558
+ try {
559
+ await Bun.write(join(cwd, "stamped.txt"), "x");
560
+ const stamp = new Date(2026, 2, 4, 9, 7, 0);
561
+ utimesSync(join(cwd, "stamped.txt"), stamp, stamp);
562
+ const pad = (n) => String(n).padStart(2, "0");
563
+ const expected = `${stamp.getFullYear()}-${pad(stamp.getMonth() + 1)}-${pad(stamp.getDate())} `
564
+ + `${pad(stamp.getHours())}:${pad(stamp.getMinutes())}`;
565
+ const long = await run("builtin lsfancy -l stamped.txt", { cwd });
566
+ expect(long.status).toBe(0);
567
+ expect(long.stdout).toContain(expected);
568
+ } finally { rmSync(cwd, { recursive: true, force: true }); }
569
+ });
570
+
571
+ test("lsfancy -l shows a symlink's target, including a broken one", async () => {
572
+ const cwd = mkdtempSync(join(tmpdir(), "bunmsh-lsfancy-symlink-"));
573
+ try {
574
+ await Bun.write(join(cwd, "target.txt"), "hi");
575
+ mkdirSync(join(cwd, "targetdir"));
576
+ symlinkSync("target.txt", join(cwd, "link_ok"));
577
+ symlinkSync("targetdir", join(cwd, "link_dir"));
578
+ symlinkSync("/nonexistent/path", join(cwd, "link_broken"));
579
+ symlinkSync("loop_b", join(cwd, "loop_a"));
580
+ symlinkSync("loop_a", join(cwd, "loop_b"));
581
+ const long = await run("builtin lsfancy -l", { cwd });
582
+ expect(long.status).toBe(0);
583
+ expect(long.stdout).toContain("link_ok -> target.txt");
584
+ expect(long.stdout).toContain("link_dir -> targetdir");
585
+ expect(long.stdout).toContain("link_broken -> /nonexistent/path");
586
+ expect(long.stdout).toContain("loop_a -> loop_b");
587
+ // Non-symlink entries get no "-> target" suffix at all.
588
+ expect(long.stdout).not.toContain("target.txt ->");
589
+ expect(long.stdout).not.toContain("targetdir/ ->");
590
+ // A working symlink still gets the plain link icon; one whose target
591
+ // doesn't resolve (missing, or a cycle) gets a distinct broken-link
592
+ // icon instead, in both the plain and long listing forms.
593
+ expect(long.stdout).toContain("🔗 link_ok");
594
+ expect(long.stdout).toContain("🚫 link_broken");
595
+ expect(long.stdout).toContain("🚫 loop_a");
596
+ expect(long.stdout).toContain("🚫 loop_b");
597
+ const plain = await run("builtin lsfancy", { cwd });
598
+ expect(plain.stdout).toContain("🔗 link_ok");
599
+ expect(plain.stdout).toContain("🚫 link_broken");
600
+ } finally { rmSync(cwd, { recursive: true, force: true }); }
601
+ });
602
+
603
+ test("fallback ls is lsfancy; Bun Shell's own ls moved to lsbun", async () => {
604
+ const cwd = mkdtempSync(join(tmpdir(), "bunmsh-ls-rename-"));
605
+ try {
606
+ await Bun.write(join(cwd, "photo.png"), "image");
607
+ const asLs = await run("builtin ls", { cwd });
608
+ expect(asLs.status).toBe(0);
609
+ expect(asLs.stdout).toContain("🖼️ photo.png");
610
+ const asLsfancy = await run("builtin lsfancy", { cwd });
611
+ expect(asLsfancy.stdout).toBe(asLs.stdout);
612
+ // Bun Shell's own implementation is still reachable, just renamed, and
613
+ // produces its old plain (no emoji) output.
614
+ const asLsbun = await run("builtin lsbun", { cwd });
615
+ expect(asLsbun.status).toBe(0);
616
+ expect(asLsbun.stdout).toContain("photo.png");
617
+ expect(asLsbun.stdout).not.toContain("🖼️");
618
+ // Errors report the name actually invoked, not a hardcoded "lsfancy".
619
+ const badFlag = await run("builtin ls -Z", { cwd });
620
+ expect(badFlag).toMatchObject({ status: 2, stdout: "", stderr: "bunmsh: ls: unsupported option: -Z\n" });
621
+ const missing = await run("builtin ls does-not-exist", { cwd });
622
+ expect(missing.status).toBe(1);
623
+ expect(missing.stderr).toContain("bunmsh: ls: does-not-exist:");
624
+ } finally { rmSync(cwd, { recursive: true, force: true }); }
625
+ });
626
+
627
+ test("fallback find filters paths and supports both -exec modes", async () => {
628
+ const cwd = mkdtempSync(join(tmpdir(), "bunmsh-find-"));
629
+ try {
630
+ mkdirSync(join(cwd, "sub"));
631
+ await Bun.write(join(cwd, "a.txt"), "a");
632
+ await Bun.write(join(cwd, "skip.js"), "js");
633
+ await Bun.write(join(cwd, "sub", "b.txt"), "b");
634
+ const filtered = await run("builtin find . -type f -name '*.txt'", { cwd });
635
+ expect(filtered).toMatchObject({
636
+ status: 0,
637
+ stdout: "./a.txt\n./sub/b.txt\n",
638
+ stderr: "",
639
+ });
640
+ const each = await run("builtin find . -type f -name '*.txt' -exec basename {} \\;", { cwd });
641
+ expect(each).toMatchObject({ status: 0, stdout: "a.txt\nb.txt\n", stderr: "" });
642
+ const batch = await run("builtin find . -type f -name '*.txt' -exec echo batch {} +", { cwd });
643
+ expect(batch).toMatchObject({
644
+ status: 0,
645
+ stdout: "batch ./a.txt ./sub/b.txt\n",
646
+ stderr: "",
647
+ });
648
+ } finally { rmSync(cwd, { recursive: true, force: true }); }
649
+ });
650
+
651
+ test("fallback grep supports matching, output modes, quiet, and recursion", async () => {
652
+ expect(await run("printf 'Alpha beta\\nnone\\nBETA\\n' | builtin grep -Ein 'beta'"))
653
+ .toMatchObject({ status: 0, stdout: "1:Alpha beta\n3:BETA\n" });
654
+ expect(await run("printf 'abc123\\n' | builtin grep -Eo '[0-9]+'"))
655
+ .toMatchObject({ status: 0, stdout: "123\n" });
656
+ expect(await run("printf 'keep\\ndrop\\n' | builtin grep -v drop"))
657
+ .toMatchObject({ status: 0, stdout: "keep\n" });
658
+ expect(await run("printf 'found\\n' | builtin grep -q found"))
659
+ .toMatchObject({ status: 0, stdout: "" });
660
+ expect(await run("printf 'red red\\n' | builtin grep --color=always red"))
661
+ .toMatchObject({
662
+ status: 0,
663
+ stdout: "\x1b[01;31mred\x1b[m \x1b[01;31mred\x1b[m\n",
664
+ });
665
+ expect(await run("printf 'red\\n' | builtin grep --color=never red"))
666
+ .toMatchObject({ status: 0, stdout: "red\n" });
667
+ expect(await run("printf 'red\\n' | builtin grep --color=always -o red"))
668
+ .toMatchObject({ status: 0, stdout: "\x1b[01;31mred\x1b[m\n" });
669
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-grep-"));
670
+ try {
671
+ mkdirSync(`${directory}/nested`);
672
+ await Bun.write(`${directory}/nested/a.txt`, "needle\n");
673
+ const recursive = await run("builtin grep -rn needle nested", { cwd: directory });
674
+ expect(recursive).toMatchObject({ status: 0, stdout: "nested/a.txt:1:needle\n" });
675
+ } finally { rmSync(directory, { recursive: true, force: true }); }
676
+ });
677
+
678
+ test("fallback head closes an infinite upstream and file utilities work", async () => {
679
+ expect(await run("yes | builtin head -n 2")).toMatchObject({ status: 0, stdout: "y\ny\n" });
680
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-utils-"));
681
+ try {
682
+ const tee = await run("printf data | builtin tee saved.txt", { cwd: directory });
683
+ expect(tee).toMatchObject({ status: 0, stdout: "data" });
684
+ expect(await Bun.file(`${directory}/saved.txt`).text()).toBe("data");
685
+ const md5 = await run("builtin md5sum saved.txt", { cwd: directory });
686
+ expect(md5.stdout).toBe("8d777f385d3dfec8815d20f7496026dc saved.txt\n");
687
+ const sha = await run("builtin sha256sum saved.txt", { cwd: directory });
688
+ expect(sha.stdout).toBe("3a6eb0790f39ac87c94f3856b2dd2c5d110e6811602261a9a923d3bb23adc8b7 saved.txt\n");
689
+ const temporary = await run("builtin mktemp -d sample.XXXXXX", { cwd: directory });
690
+ const created = temporary.stdout.trim();
691
+ expect(created.startsWith(`${directory}/sample.`)).toBe(true);
692
+ expect(await run(`builtin rmdir ${created}`, { cwd: directory })).toMatchObject({ status: 0 });
693
+ expect(await Bun.file(created).exists()).toBe(false);
694
+ expect(await run("builtin clear")).toMatchObject({ stdout: "\x1b[2J\x1b[H" });
695
+ } finally { rmSync(directory, { recursive: true, force: true }); }
696
+ });
697
+
698
+ test("reflects bunmsh and process.argv0 through fallback commands", async () => {
699
+ const runInTerminal = async (source) => {
700
+ let transcript = "";
701
+ const terminal = new Bun.Terminal({
702
+ cols: 80,
703
+ rows: 24,
704
+ data(_terminal, data) { transcript += data.toString(); },
705
+ });
706
+ const proc = Bun.spawn({
707
+ cmd: [process.execPath, "src/main.js", "-c", source],
708
+ cwd: new URL("..", import.meta.url).pathname,
709
+ env: { ...process.env, PATH: "/no/such/path" },
710
+ terminal,
711
+ });
712
+ try {
713
+ return { status: await proc.exited, transcript };
714
+ } finally { terminal.close(); }
715
+ };
716
+
717
+ expect(await runInTerminal("bunmsh -cc printf nested"))
718
+ .toEqual({ status: 0, transcript: "nested" });
719
+ expect((await runInTerminal("bun --version"))).toEqual({
720
+ status: 0,
721
+ transcript: `${Bun.version}\r\n`,
722
+ });
723
+ });
724
+
725
+ test("env recursively dispatches env commands with isolated assignments", async () => {
726
+ const chained = await run("env env a=1 env b=2");
727
+ expect(chained.status).toBe(0);
728
+ expect(chained.stdout.split("\n")).toContain("a=1");
729
+ expect(chained.stdout.split("\n")).toContain("b=2");
730
+ expect(chained.state.env.a).toBeUndefined();
731
+ expect(chained.state.env.b).toBeUndefined();
732
+
733
+ const clean = await run("env -i a=1 env b=2");
734
+ expect(clean.stdout.split("\n").filter(Boolean).sort()).toEqual(["a=1", "b=2"]);
735
+ });
736
+
737
+ test("supports if, elif, negation, functions, and set --", async () => {
738
+ const script = `
739
+ show_value() {
740
+ if [ "$1" = "yes" ] ; then
741
+ printf 'fn:%s' "$2"
742
+ else
743
+ printf bad
744
+ fi
745
+ }
746
+ set -- alpha beta
747
+ if ! [ "$1" = "wrong" ] && [ "$2" = "beta" ] ; then
748
+ show_value yes nested
749
+ elif [ "$1" = "alpha" ] ; then
750
+ printf elif
751
+ else
752
+ printf else
753
+ fi
754
+ `;
755
+ expect(await run(script)).toMatchObject({ status: 0, stdout: "fn:nested", stderr: "" });
756
+ expect(await run("! false; printf $?")).toMatchObject({ status: 0, stdout: "0" });
757
+ });
758
+
759
+ test("exec stops the current shell flow and fd duplication redirects output", async () => {
760
+ const execution = await run("printf before; exec printf after; printf never");
761
+ expect(execution).toMatchObject({ status: 0, stdout: "beforeafter", stderr: "" });
762
+ expect(execution.state.exitRequested).toBe(true);
763
+ expect(await run("printf error 1>&2")).toMatchObject({ status: 0, stdout: "", stderr: "error" });
764
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-fd-dup-"));
765
+ try {
766
+ const merged = await run("builtin cat missing-file 2>&1", { cwd: directory });
767
+ expect(merged).toMatchObject({ status: 1, stderr: "" });
768
+ expect(merged.stdout).toContain("bunmsh: cat: missing-file:");
769
+ expect(await Bun.file(join(directory, "&1")).exists()).toBe(false);
770
+ } finally { rmSync(directory, { recursive: true, force: true }); }
771
+ });
772
+
773
+ test("fallback script utilities cover required head grep cut ln chmod and uname forms", async () => {
774
+ expect(await run("printf abcdef | builtin head -c 3")).toMatchObject({ stdout: "abc" });
775
+ expect(await run("printf 'exact\\nextra\\n' | builtin grep -qFx exact")).toMatchObject({ status: 0, stdout: "" });
776
+ expect(await run("printf '123456789\\n' | builtin cut -c6-")).toMatchObject({ stdout: "6789\n" });
777
+ expect(await run("builtin uname -m")).toMatchObject({ status: 0 });
778
+ const windows = runUnameFallback(["uname", "-mprs"], {
779
+ arch: "x64",
780
+ type: "Windows_NT",
781
+ hostname: "windows-host",
782
+ release: "10.0.26100",
783
+ version: "Windows 11 Pro",
784
+ });
785
+ expect(decode(windows.stdout)).toBe("Windows_NT 10.0.26100 x86_64 x86_64\n");
786
+ const directory = mkdtempSync(join(tmpdir(), "bunmsh-script-tools-"));
787
+ try {
788
+ await Bun.write(`${directory}/source`, "one");
789
+ await Bun.write(`${directory}/other`, "two");
790
+ expect(await run("builtin ln -sfT source link", { cwd: directory })).toMatchObject({ status: 0 });
791
+ expect(readlinkSync(`${directory}/link`)).toBe("source");
792
+ expect(await run("builtin ln -sfT other link", { cwd: directory })).toMatchObject({ status: 0 });
793
+ expect(readlinkSync(`${directory}/link`)).toBe("other");
794
+ expect(await run("builtin chmod 777 source; builtin chmod +x other", { cwd: directory }))
795
+ .toMatchObject({ status: 0 });
796
+ expect(statSync(`${directory}/source`).mode & 0o777).toBe(0o777);
797
+ expect(statSync(`${directory}/other`).mode & 0o111).toBe(0o111);
798
+ } finally { rmSync(directory, { recursive: true, force: true }); }
799
+ });
800
+
801
+ test("evaluates raw Bun. lines before shell parsing and expansion", async () => {
802
+ const output = await run(` Bun.version + " $HOME * ; raw"`);
803
+ expect(output.status).toBe(0);
804
+ expect(output.stdout).toBe(`${Bun.version} $HOME * ; raw\n`);
805
+ expect(output.stderr).toBe("");
806
+ });
807
+
808
+ test("awaits Bun. eval results, suppresses undefined, and reports errors", async () => {
809
+ const empty = await run("Bun.sleep(0)");
810
+ expect(empty).toMatchObject({ status: 0, stdout: "", stderr: "" });
811
+
812
+ const failure = await run("Bun.thisMethodDoesNotExist()");
813
+ expect(failure.status).toBe(1);
814
+ expect(failure.stdout).toBe("");
815
+ expect(failure.stderr).toContain("TypeError");
816
+ });
817
+
818
+ test("runs Bun. eval with the active shell cwd and restores the process cwd", async () => {
819
+ const cwd = mkdtempSync(join(tmpdir(), "bunmsh-js-cwd-"));
820
+ const previousCwd = process.cwd();
821
+ try {
822
+ await Bun.write(join(cwd, "relative-marker.txt"), "cwd-marker");
823
+ const shown = await run("Bun.e, process.cwd()", { cwd });
824
+ expect(shown).toMatchObject({ status: 0, stdout: `${cwd}\n`, stderr: "" });
825
+ const relative = await run('Bun.file("relative-marker.txt").text()', { cwd });
826
+ expect(relative).toMatchObject({ status: 0, stdout: "cwd-marker\n", stderr: "" });
827
+ expect(process.cwd()).toBe(previousCwd);
828
+ } finally { rmSync(cwd, { recursive: true, force: true }); }
829
+ });
830
+
831
+ test("provides color aliases for common commands", () => {
832
+ const state = createState();
833
+ // toybox diff takes a bare --color; it has no =auto form.
834
+ expect(state.aliases).toEqual({
835
+ ls: ["ls", "--color=auto"],
836
+ diff: ["diff", "--color"],
837
+ grep: ["grep", "--color=auto"],
838
+ });
839
+ });
840
+
841
+ test("expands variables while respecting single quotes", async () => {
842
+ const output = await run(`X=world; print -r -- "hello $X"; print -r -- '$X'`);
843
+ expect(output.stdout).toBe("hello world\n$X\n");
844
+ });
845
+
846
+ test("supports status connectors", async () => {
847
+ const output = await run("false && echo no; false || echo yes; true && echo done");
848
+ expect(output.stdout).toBe("yes\ndone\n");
849
+ expect(output.status).toBe(0);
850
+ });
851
+
852
+ test("runs external pipelines through Bun.spawn", async () => {
853
+ const output = await run("printf hello | tr a-z A-Z");
854
+ expect(output.stdout).toBe("HELLO");
855
+ expect(output.stderr).toBe("");
856
+ expect(output.status).toBe(0);
857
+ });
858
+
859
+ test("keeps builtin state outside pipelines", async () => {
860
+ const output = await run("export BUNMSH_TEST=value; print -r -- $BUNMSH_TEST");
861
+ expect(output.stdout).toBe("value\n");
862
+ expect(output.state.env.BUNMSH_TEST).toBe("value");
863
+ });
864
+
865
+ test("supports cd - and previous-child navigation", async () => {
866
+ const cwd = process.cwd();
867
+ const previous = await run("cd src; cd -; pwd", { cwd });
868
+ expect(previous.stdout).toBe(`${cwd}\n${cwd}\n`);
869
+ expect(previous.state.env.OLDPWD).toBe(`${cwd}/src`);
870
+
871
+ const child = await run("cd src; cd ..; //; pwd", { cwd });
872
+ expect(child.stdout).toBe(`${cwd}/src\n`);
873
+ expect(child.state.cwd).toBe(`${cwd}/src`);
874
+ });
875
+
876
+ test("treats .. as cd ..", async () => {
877
+ const cwd = process.cwd();
878
+ const output = await run("cd src; ..; pwd", { cwd });
879
+ expect(output.stdout).toBe(`${cwd}\n`);
880
+ expect(output.state.cwd).toBe(cwd);
881
+ expect(output.state.env.OLDPWD).toBe(`${cwd}/src`);
882
+ });
883
+
884
+ test("treats standalone - as cd -", async () => {
885
+ const cwd = process.cwd();
886
+ const output = await run("cd src; -; pwd", { cwd });
887
+ expect(output.stdout).toBe(`${cwd}\n${cwd}\n`);
888
+ expect(output.state.cwd).toBe(cwd);
889
+ expect(output.state.env.OLDPWD).toBe(`${cwd}/src`);
890
+ });
891
+
892
+ test("treats standalone ~ as cd HOME", async () => {
893
+ const cwd = process.cwd();
894
+ const home = cwd.slice(0, cwd.lastIndexOf("/"));
895
+ const output = await run("cd src; ~; pwd", { cwd, env: { HOME: home } });
896
+ expect(output.stdout).toBe(`${home}\n`);
897
+ expect(output.state.cwd).toBe(home);
898
+ expect(output.state.env.OLDPWD).toBe(`${cwd}/src`);
899
+ });
900
+
901
+ test("// reports a missing child and continues", async () => {
902
+ const output = await run("//; print still-running");
903
+ expect(output.stdout).toBe("still-running\n");
904
+ expect(output.stderr).toBe("bunmsh: //: no previous child directory\n");
905
+ expect(output.status).toBe(0);
906
+ });
907
+
908
+ test("exposes positional parameters and status", async () => {
909
+ const output = await run("false; print -r -- $0 $1 $# $?", {
910
+ args: ["script", "arg"],
911
+ });
912
+ expect(output.stdout).toBe("script arg 1 1\n");
913
+ });
914
+
915
+ test("a single question mark prints the previous status and succeeds", async () => {
916
+ const failed = await run("false");
917
+ const execution = await execute("?", failed.state, { capture: true });
918
+ const output = {
919
+ ...execution,
920
+ stdout: decode(execution.stdout),
921
+ stderr: decode(execution.stderr),
922
+ };
923
+ expect(output).toMatchObject({ status: 0, stdout: "1\n", stderr: "" });
924
+ expect(failed.state.lastStatus).toBe(0);
925
+ expect(await run("?")).toMatchObject({ status: 0, stdout: "0\n", stderr: "" });
926
+ });
927
+
928
+ test("tab creates cwd-only workspaces and cycles between them", async () => {
929
+ const cwd = process.cwd();
930
+ const output = await run("tab; cd src; tab; pwd; tab; pwd", { cwd });
931
+ expect(output.stdout).toBe(`${cwd}\n${cwd}/src\n`);
932
+ expect(output.state.tabs).toEqual([cwd, `${cwd}/src`]);
933
+ expect(output.state.activeTab).toBe(1);
934
+ expect(output.state.cwd).toBe(`${cwd}/src`);
935
+ expect(output.state.env.OLDPWD).toBe(cwd);
936
+ });
937
+
938
+ test("tab supports new, numbered, left, right, and close operations", async () => {
939
+ const cwd = process.cwd();
940
+ const output = await run(
941
+ "tab n; cd src; tab n; cd ../test; tab 1; tab r; pwd; tab l; pwd; " +
942
+ "tab 3; pwd; tab x; pwd",
943
+ { cwd },
944
+ );
945
+ expect(output.stdout).toBe(`${cwd}/src\n${cwd}\n${cwd}/test\n${cwd}/src\n`);
946
+ expect(output.state.tabs).toEqual([cwd, `${cwd}/src`]);
947
+ expect(output.state.activeTab).toBe(1);
948
+ expect(output.state.cwd).toBe(`${cwd}/src`);
949
+ });
950
+
951
+ test("tab c closes the active tab like tab x", async () => {
952
+ const output = await run("tab n; tab c");
953
+ expect(output.status).toBe(0);
954
+ expect(output.state.tabs).toHaveLength(1);
955
+ expect(output.state.activeTab).toBe(0);
956
+ });
957
+
958
+ test("tab mouse toggles and explicitly sets mouse tracking", async () => {
959
+ let output = await run("tab mouse", { mouseTracking: false });
960
+ expect(output.state.mouseTracking).toBe(true);
961
+ output = await run("tab mouse off", { mouseTracking: true });
962
+ expect(output.state.mouseTracking).toBe(false);
963
+ output = await run("tab mouse true", { mouseTracking: false });
964
+ expect(output.state.mouseTracking).toBe(true);
965
+ output = await run("tab mouse false", { mouseTracking: true });
966
+ expect(output.state.mouseTracking).toBe(false);
967
+ expect(await run("tab mouse maybe")).toMatchObject({
968
+ status: 1,
969
+ stderr: "bunmsh: tab: mouse: expected on, off, true, or false\n",
970
+ });
971
+ });
972
+
973
+ test("tab path toggles and explicitly controls PATH lookup", async () => {
974
+ let output = await run("tab path; sh -c 'echo external'; printf builtin");
975
+ expect(output.state.pathSearch).toBe(false);
976
+ expect(output.stdout).toBe("builtin");
977
+ expect(output.stderr).toContain("bunmsh: sh: not found");
978
+
979
+ output = await run("tab path off; tab path on; sh -c 'printf external'");
980
+ expect(output.state.pathSearch).toBe(true);
981
+ expect(output.stdout).toBe("external");
982
+
983
+ output = await run("tab path false; printf fallback-ok");
984
+ expect(output.state.pathSearch).toBe(false);
985
+ expect(output.stdout).toBe("fallback-ok");
986
+ expect(await run("tab path maybe")).toMatchObject({
987
+ status: 1,
988
+ stderr: "bunmsh: tab: path: expected on, off, true, or false\n",
989
+ });
990
+ });
991
+
992
+ test("which still searches PATH while direct PATH lookup is disabled", async () => {
993
+ const shell = Bun.which("sh");
994
+ expect(shell).toBeTruthy();
995
+ const output = await run("tab path off; which sh; \"$(which sh)\" -c 'printf explicit-path'");
996
+ expect(output.status).toBe(0);
997
+ expect(output.stdout).toBe(`${shell}\nexplicit-path`);
998
+ expect(output.stderr).toBe("");
999
+ });
1000
+
1001
+ test("tab rejects invalid selection and closing the final tab", async () => {
1002
+ const missing = await run("tab 2");
1003
+ expect(missing.status).toBe(1);
1004
+ expect(missing.stderr).toBe("bunmsh: tab: 2: no such tab\n");
1005
+
1006
+ const last = await run("tab x");
1007
+ expect(last.status).toBe(1);
1008
+ expect(last.stderr).toBe("bunmsh: tab: cannot close the last tab\n");
1009
+ });
1010
+
1011
+ test("tab save persists bunmsh history only when requested", async () => {
1012
+ const home = mkdtempSync(join(tmpdir(), "bunmsh-own-history-"));
1013
+ try {
1014
+ const env = { HOME: home, BUNMSH_IMPORT_HISTORY: "off" };
1015
+ const saved = await run("tab save", {
1016
+ env,
1017
+ history: ["echo first", "echo duplicate", "echo duplicate", "echo last"],
1018
+ });
1019
+ const path = join(home, ".local", "share", "bunmsh", "history");
1020
+ expect(saved).toMatchObject({ status: 0, stdout: `${path}\n`, stderr: "" });
1021
+ // The plain save appends everything as-is, one JSON value per line —
1022
+ // it does not dedupe; that is what `tab save d` is for.
1023
+ expect(Bun.JSONL.parse(await Bun.file(path).text()))
1024
+ .toEqual(["echo first", "echo duplicate", "echo duplicate", "echo last"]);
1025
+ // Reading history back still dedupes in memory (keeping the most
1026
+ // recent occurrence), regardless of what is actually on disk.
1027
+ expect(await importedHistory(env)).toEqual(["echo first", "echo duplicate", "echo last"]);
1028
+ } finally { rmSync(home, { recursive: true, force: true }); }
1029
+ });
1030
+
1031
+ test("saveBunmshHistory from two sessions never clobbers the other's entries", async () => {
1032
+ const home = mkdtempSync(join(tmpdir(), "bunmsh-history-concurrent-"));
1033
+ try {
1034
+ const env = { HOME: home, BUNMSH_IMPORT_HISTORY: "off" };
1035
+ // Two independent sessions, as if two bunmsh processes were running at
1036
+ // once: each only knows about its own new commands (historySaved: 0),
1037
+ // not about anything the other has written.
1038
+ const sessionA = { history: ["a1", "a2"], historySaved: 0 };
1039
+ const sessionB = { history: ["b1", "b2"], historySaved: 0 };
1040
+ await saveBunmshHistory(sessionA, env);
1041
+ await saveBunmshHistory(sessionB, env);
1042
+ expect(await importedHistory(env)).toEqual(["a1", "a2", "b1", "b2"]);
1043
+ // A keeps going and saves again; B's earlier entries must still be
1044
+ // there — a second save from one session must not touch what the
1045
+ // other already wrote (this is the whole point of appending instead
1046
+ // of rewriting the file).
1047
+ sessionA.history.push("a3");
1048
+ await saveBunmshHistory(sessionA, env);
1049
+ expect(await importedHistory(env)).toEqual(["a1", "a2", "b1", "b2", "a3"]);
1050
+ } finally { rmSync(home, { recursive: true, force: true }); }
1051
+ });
1052
+
1053
+ test("tab save d dedupes the whole history file", async () => {
1054
+ const home = mkdtempSync(join(tmpdir(), "bunmsh-history-dedupe-"));
1055
+ try {
1056
+ const env = { HOME: home, BUNMSH_IMPORT_HISTORY: "off" };
1057
+ await saveBunmshHistory({ history: ["x", "y", "x", "z"], historySaved: 0 }, env);
1058
+ const deduped = await run("tab s d", { env, history: [] });
1059
+ const path = join(home, ".local", "share", "bunmsh", "history");
1060
+ expect(deduped).toMatchObject({ status: 0, stderr: "" });
1061
+ expect(deduped.stdout).toContain(`${path}: 3 unique entries`);
1062
+ expect(Bun.JSONL.parse(await Bun.file(path).text())).toEqual(["y", "x", "z"]);
1063
+ } finally { rmSync(home, { recursive: true, force: true }); }
1064
+ });
1065
+
1066
+ test("tab save rejects an unknown modifier", async () => {
1067
+ expect(await run("tab s bogus")).toMatchObject({
1068
+ status: 1,
1069
+ stderr: "bunmsh: tab: save: expected d or dedupe\n",
1070
+ });
1071
+ });
1072
+
1073
+ test("saveBunmshHistory migrates a legacy JSON-array history file to JSONL", async () => {
1074
+ const home = mkdtempSync(join(tmpdir(), "bunmsh-history-migrate-"));
1075
+ try {
1076
+ const env = { HOME: home, BUNMSH_IMPORT_HISTORY: "off" };
1077
+ const path = join(home, ".local", "share", "bunmsh", "history");
1078
+ mkdirSync(join(home, ".local", "share", "bunmsh"), { recursive: true });
1079
+ await Bun.write(path, `${JSON.stringify(["old1", "old2"], null, 2)}\n`);
1080
+ expect(await importedHistory(env)).toEqual(["old1", "old2"]);
1081
+ await saveBunmshHistory({ history: ["new1"], historySaved: 0 }, env);
1082
+ const text = await Bun.file(path).text();
1083
+ expect(text.trimStart().startsWith("[")).toBe(false);
1084
+ expect(Bun.JSONL.parse(text)).toEqual(["old1", "old2", "new1"]);
1085
+ } finally { rmSync(home, { recursive: true, force: true }); }
1086
+ });
1087
+ });