@jerryan/just-bash 3.6.0 → 3.7.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 (243) hide show
  1. package/CHANGELOG.md +349 -316
  2. package/LICENSE +201 -201
  3. package/README.md +827 -827
  4. package/dist/agent-sandbox.d.ts +5 -0
  5. package/dist/bin/chunks/chmod-G2BCCQGF.js +3 -0
  6. package/dist/bin/chunks/{chunk-B2GCIQI2.js → chunk-2UKTHDUM.js} +1 -1
  7. package/dist/bin/{shell/chunks/chunk-7WBCA2BB.js → chunks/chunk-3DWQCLNP.js} +1 -1
  8. package/dist/bin/chunks/chunk-66UHJFN6.js +11 -0
  9. package/dist/bin/{shell/chunks/chunk-67XYNGRV.js → chunks/chunk-6O4Z6BQT.js} +1 -1
  10. package/dist/bin/chunks/{chunk-QFTZKD5O.js → chunk-6TUILMPB.js} +1 -1
  11. package/dist/bin/chunks/{chunk-M7SIPZZZ.js → chunk-7KMOGI3N.js} +1 -1
  12. package/dist/bin/{shell/chunks/chunk-6ESRNSO7.js → chunks/chunk-ADI36B7X.js} +1 -1
  13. package/dist/bin/chunks/chunk-CN4JKMTR.js +8 -0
  14. package/dist/bin/{shell/chunks/chunk-DZAFUADN.js → chunks/chunk-E26NQEH2.js} +1 -1
  15. package/dist/bin/chunks/chunk-E54Z6VIE.js +12 -0
  16. package/dist/bin/chunks/chunk-F2PYTUMR.js +9 -0
  17. package/dist/bin/chunks/chunk-FO7XJH3J.js +13 -0
  18. package/dist/bin/chunks/chunk-HWK7KFGB.js +3 -0
  19. package/dist/bin/{shell/chunks/chunk-LE2XKKGQ.js → chunks/chunk-HYLF56CC.js} +1 -1
  20. package/dist/bin/chunks/chunk-KNTDFP7X.js +12 -0
  21. package/dist/bin/{shell/chunks/chunk-MF3GVFLC.js → chunks/chunk-L345YZ6R.js} +1 -1
  22. package/dist/bin/chunks/chunk-NBTZL3VS.js +3 -0
  23. package/dist/bin/chunks/chunk-OHFB3M3X.js +3 -0
  24. package/dist/bin/{shell/chunks/chunk-HQ63MFHG.js → chunks/chunk-PEUGMGJJ.js} +1 -1
  25. package/dist/bin/chunks/chunk-QKJAAJ7J.js +3 -0
  26. package/dist/bin/{shell/chunks/chunk-JELR4642.js → chunks/chunk-R76AK3KD.js} +12 -12
  27. package/dist/bin/chunks/{chunk-NLU5LALY.js → chunk-RRECHBUS.js} +1 -1
  28. package/dist/bin/chunks/{chunk-ZMGLTHSU.js → chunk-THFQI5LV.js} +1 -1
  29. package/dist/bin/chunks/{chunk-CL7IYCGG.js → chunk-U7YR5CDD.js} +1 -1
  30. package/dist/bin/chunks/cp-TMDR6USI.js +3 -0
  31. package/dist/bin/chunks/du-UKFUX7KM.js +3 -0
  32. package/dist/bin/chunks/find-W2RZWTOF.js +3 -0
  33. package/dist/bin/chunks/{flag-coverage-C7PB2MO7.js → flag-coverage-QJ5ZQKCF.js} +1 -1
  34. package/dist/bin/{shell/chunks/grep-CVU5V66H.js → chunks/grep-IHDO3L72.js} +1 -1
  35. package/dist/bin/chunks/gzip-WUK63QLL.js +3 -0
  36. package/dist/bin/{shell/chunks/js-exec-DJQLXWCS.js → chunks/js-exec-BE37X4L2.js} +7 -7
  37. package/dist/bin/chunks/js-exec-worker.js +296 -116
  38. package/dist/bin/chunks/ln-XVC53673.js +3 -0
  39. package/dist/bin/chunks/ls-EROTXGTC.js +3 -0
  40. package/dist/bin/chunks/mkdir-YJ3SOVRP.js +3 -0
  41. package/dist/bin/chunks/mv-HDNKXPO6.js +3 -0
  42. package/dist/bin/{shell/chunks/python3-JCJHSX4Z.js → chunks/python3-TJ6DCPIA.js} +1 -1
  43. package/dist/bin/chunks/readlink-ZUIECKQC.js +3 -0
  44. package/dist/bin/chunks/rg-ODJAYIKX.js +3 -0
  45. package/dist/bin/chunks/rm-B4LVIG7A.js +3 -0
  46. package/dist/bin/chunks/rmdir-W5NBOJ7E.js +3 -0
  47. package/dist/bin/{shell/chunks/sleep-DVFE2GSF.js → chunks/sleep-MOJQBZMY.js} +1 -1
  48. package/dist/bin/chunks/split-TVJYLTIJ.js +3 -0
  49. package/dist/bin/chunks/sqlite3-5BGAK7VX.js +3 -0
  50. package/dist/bin/chunks/{timeout-YGFHQJKX.js → timeout-RQOWSWYG.js} +1 -1
  51. package/dist/bin/chunks/worker.js +233 -108
  52. package/dist/bin/just-bash.js +381 -376
  53. package/dist/bin/shell/chunks/chmod-G2BCCQGF.js +3 -0
  54. package/dist/bin/shell/chunks/{chunk-B2GCIQI2.js → chunk-2UKTHDUM.js} +1 -1
  55. package/dist/bin/{chunks/chunk-7WBCA2BB.js → shell/chunks/chunk-3DWQCLNP.js} +1 -1
  56. package/dist/bin/shell/chunks/chunk-66UHJFN6.js +11 -0
  57. package/dist/bin/{chunks/chunk-67XYNGRV.js → shell/chunks/chunk-6O4Z6BQT.js} +1 -1
  58. package/dist/bin/shell/chunks/{chunk-QFTZKD5O.js → chunk-6TUILMPB.js} +1 -1
  59. package/dist/bin/shell/chunks/{chunk-M7SIPZZZ.js → chunk-7KMOGI3N.js} +1 -1
  60. package/dist/bin/{chunks/chunk-6ESRNSO7.js → shell/chunks/chunk-ADI36B7X.js} +1 -1
  61. package/dist/bin/shell/chunks/chunk-CN4JKMTR.js +8 -0
  62. package/dist/bin/{chunks/chunk-DZAFUADN.js → shell/chunks/chunk-E26NQEH2.js} +1 -1
  63. package/dist/bin/shell/chunks/chunk-E54Z6VIE.js +12 -0
  64. package/dist/bin/shell/chunks/chunk-F2PYTUMR.js +9 -0
  65. package/dist/bin/shell/chunks/chunk-FO7XJH3J.js +13 -0
  66. package/dist/bin/shell/chunks/chunk-HWK7KFGB.js +3 -0
  67. package/dist/bin/{chunks/chunk-LE2XKKGQ.js → shell/chunks/chunk-HYLF56CC.js} +1 -1
  68. package/dist/bin/shell/chunks/chunk-KNTDFP7X.js +12 -0
  69. package/dist/bin/{chunks/chunk-MF3GVFLC.js → shell/chunks/chunk-L345YZ6R.js} +1 -1
  70. package/dist/bin/shell/chunks/chunk-NBTZL3VS.js +3 -0
  71. package/dist/bin/shell/chunks/chunk-OHFB3M3X.js +3 -0
  72. package/dist/bin/{chunks/chunk-HQ63MFHG.js → shell/chunks/chunk-PEUGMGJJ.js} +1 -1
  73. package/dist/bin/shell/chunks/chunk-QKJAAJ7J.js +3 -0
  74. package/dist/bin/{chunks/chunk-JELR4642.js → shell/chunks/chunk-R76AK3KD.js} +12 -12
  75. package/dist/bin/shell/chunks/{chunk-NLU5LALY.js → chunk-RRECHBUS.js} +1 -1
  76. package/dist/bin/shell/chunks/{chunk-ZMGLTHSU.js → chunk-THFQI5LV.js} +1 -1
  77. package/dist/bin/shell/chunks/{chunk-CL7IYCGG.js → chunk-U7YR5CDD.js} +1 -1
  78. package/dist/bin/shell/chunks/cp-TMDR6USI.js +3 -0
  79. package/dist/bin/shell/chunks/du-UKFUX7KM.js +3 -0
  80. package/dist/bin/shell/chunks/find-W2RZWTOF.js +3 -0
  81. package/dist/bin/shell/chunks/{flag-coverage-C7PB2MO7.js → flag-coverage-QJ5ZQKCF.js} +1 -1
  82. package/dist/bin/{chunks/grep-CVU5V66H.js → shell/chunks/grep-IHDO3L72.js} +1 -1
  83. package/dist/bin/shell/chunks/gzip-WUK63QLL.js +3 -0
  84. package/dist/bin/{chunks/js-exec-DJQLXWCS.js → shell/chunks/js-exec-BE37X4L2.js} +7 -7
  85. package/dist/bin/shell/chunks/ln-XVC53673.js +3 -0
  86. package/dist/bin/shell/chunks/ls-EROTXGTC.js +3 -0
  87. package/dist/bin/shell/chunks/mkdir-YJ3SOVRP.js +3 -0
  88. package/dist/bin/shell/chunks/mv-HDNKXPO6.js +3 -0
  89. package/dist/bin/{chunks/python3-JCJHSX4Z.js → shell/chunks/python3-TJ6DCPIA.js} +1 -1
  90. package/dist/bin/shell/chunks/readlink-ZUIECKQC.js +3 -0
  91. package/dist/bin/shell/chunks/rg-ODJAYIKX.js +3 -0
  92. package/dist/bin/shell/chunks/rm-B4LVIG7A.js +3 -0
  93. package/dist/bin/shell/chunks/rmdir-W5NBOJ7E.js +3 -0
  94. package/dist/bin/{chunks/sleep-DVFE2GSF.js → shell/chunks/sleep-MOJQBZMY.js} +1 -1
  95. package/dist/bin/shell/chunks/split-TVJYLTIJ.js +3 -0
  96. package/dist/bin/shell/chunks/sqlite3-5BGAK7VX.js +3 -0
  97. package/dist/bin/shell/chunks/{timeout-YGFHQJKX.js → timeout-RQOWSWYG.js} +1 -1
  98. package/dist/bin/shell/shell.js +385 -380
  99. package/dist/bundle/browser.js +643 -638
  100. package/dist/bundle/chunks/chmod-XZNKTJHL.js +2 -0
  101. package/dist/bundle/chunks/{chunk-XVSR5HHH.js → chunk-2T7PBFL4.js} +1 -1
  102. package/dist/bundle/chunks/chunk-3BMWRGU2.js +10 -0
  103. package/dist/bundle/chunks/chunk-3CIDHL5V.js +11 -0
  104. package/dist/bundle/chunks/chunk-4CC3OZPU.js +2 -0
  105. package/dist/bundle/chunks/{chunk-FIMF2TLE.js → chunk-5DMO6LFU.js} +12 -12
  106. package/dist/bundle/chunks/{chunk-N3A4JVFJ.js → chunk-6IA4DXG2.js} +1 -1
  107. package/dist/bundle/chunks/chunk-A257L6QO.js +7 -0
  108. package/dist/bundle/chunks/{chunk-6DDRR56B.js → chunk-ACVD6PQF.js} +1 -1
  109. package/dist/bundle/chunks/chunk-BS6EJR2R.js +11 -0
  110. package/dist/bundle/chunks/chunk-D5FHVW27.js +2 -0
  111. package/dist/bundle/chunks/{chunk-24NLAR7R.js → chunk-E3ABCXE4.js} +1 -1
  112. package/dist/bundle/chunks/{chunk-FSJ6TTCC.js → chunk-HMM3NGUJ.js} +1 -1
  113. package/dist/bundle/chunks/chunk-IYJLVOVE.js +12 -0
  114. package/dist/bundle/chunks/chunk-LRFR25IP.js +8 -0
  115. package/dist/bundle/chunks/{chunk-NBNI7G66.js → chunk-OPYVVD5P.js} +1 -1
  116. package/dist/bundle/chunks/{chunk-F6XU52K3.js → chunk-OR544SGH.js} +1 -1
  117. package/dist/bundle/chunks/{chunk-RPKJJFGZ.js → chunk-PMBXJ3OQ.js} +1 -1
  118. package/dist/bundle/chunks/chunk-PS2RJNZZ.js +2 -0
  119. package/dist/bundle/chunks/{chunk-UC76ZOWM.js → chunk-SBOTR4JQ.js} +1 -1
  120. package/dist/bundle/chunks/chunk-T5ZEIOJ3.js +2 -0
  121. package/dist/bundle/chunks/{chunk-DMWNBCXJ.js → chunk-TLPMB3FO.js} +1 -1
  122. package/dist/bundle/chunks/{chunk-XV2V56NQ.js → chunk-YFFU74KY.js} +1 -1
  123. package/dist/bundle/chunks/{chunk-DAKEIWT3.js → chunk-YNYC232D.js} +1 -1
  124. package/dist/bundle/chunks/{chunk-ZXFELXJH.js → chunk-YUOBBH7P.js} +1 -1
  125. package/dist/bundle/chunks/cp-NWITRTH3.js +2 -0
  126. package/dist/bundle/chunks/du-IFLWEM6M.js +2 -0
  127. package/dist/bundle/chunks/find-EW6OHRPJ.js +2 -0
  128. package/dist/bundle/chunks/{flag-coverage-XTIQGK65.js → flag-coverage-PIF5QRO7.js} +1 -1
  129. package/dist/bundle/chunks/{grep-4AYF3A5J.js → grep-QDFNKAUW.js} +1 -1
  130. package/dist/bundle/chunks/gzip-HBDKZBIP.js +2 -0
  131. package/dist/bundle/chunks/{js-exec-XKF2B7C3.js → js-exec-IREGAOMH.js} +7 -7
  132. package/dist/bundle/chunks/js-exec-worker.js +296 -116
  133. package/dist/bundle/chunks/ln-CEM7GDB5.js +2 -0
  134. package/dist/bundle/chunks/ls-WJ7EIFVM.js +2 -0
  135. package/dist/bundle/chunks/mkdir-Z6MMWH3D.js +2 -0
  136. package/dist/bundle/chunks/mv-E2NFLGRQ.js +2 -0
  137. package/dist/bundle/chunks/{python3-F5S5TYGS.js → python3-W4UMQJAQ.js} +1 -1
  138. package/dist/bundle/chunks/readlink-XCFO7YD2.js +2 -0
  139. package/dist/bundle/chunks/rg-J7XDRV3B.js +2 -0
  140. package/dist/bundle/chunks/rm-IGPLE632.js +2 -0
  141. package/dist/bundle/chunks/rmdir-UMUDM2L2.js +2 -0
  142. package/dist/bundle/chunks/{sleep-PPRBTSVR.js → sleep-25QUPVDK.js} +1 -1
  143. package/dist/bundle/chunks/split-D4HPO4G5.js +2 -0
  144. package/dist/bundle/chunks/sqlite3-3HL2ECCQ.js +2 -0
  145. package/dist/bundle/chunks/{timeout-C6WDYPLV.js → timeout-37GM7IIL.js} +1 -1
  146. package/dist/bundle/chunks/worker.js +233 -108
  147. package/dist/bundle/index.cjs +975 -970
  148. package/dist/bundle/index.js +357 -352
  149. package/dist/commands/js-exec/js-exec.d.ts +4 -0
  150. package/dist/commands/worker-bridge/bridge-handler.d.ts +9 -3
  151. package/dist/commands/worker-bridge/protocol.d.ts +72 -21
  152. package/dist/commands/worker-bridge/sync-backend.d.ts +3 -0
  153. package/dist/fs/fs-error.d.ts +43 -0
  154. package/dist/fs/interface.d.ts +13 -0
  155. package/dist/fs/mountable-fs/mountable-fs.d.ts +20 -0
  156. package/dist/fs/overlay-fs/apply.d.ts +15 -1
  157. package/dist/fs/overlay-fs/index.d.ts +1 -0
  158. package/dist/fs/overlay-fs/overlay-fs.d.ts +31 -0
  159. package/dist/fs/overlay-fs/overlay-tree.d.ts +39 -0
  160. package/dist/fs/path-utils.d.ts +5 -0
  161. package/dist/fs/vfs-template.d.ts +74 -0
  162. package/dist/index.d.cts +3 -1
  163. package/dist/index.d.ts +3 -1
  164. package/dist/interpreter/builtin-dispatch.d.ts +10 -0
  165. package/dist/interpreter/builtin-manifest.d.ts +273 -0
  166. package/dist/interpreter/builtins/help.d.ts +6 -0
  167. package/dist/interpreter/builtins/shopt.d.ts +3 -0
  168. package/dist/interpreter/helpers/shell-constants.d.ts +0 -20
  169. package/dist/timers.d.ts +9 -0
  170. package/package.json +135 -136
  171. package/vendor/cpython-emscripten/python.cjs +2 -2
  172. package/dist/bin/chunks/chmod-WYYTXGVB.js +0 -3
  173. package/dist/bin/chunks/chunk-43E7AR6A.js +0 -3
  174. package/dist/bin/chunks/chunk-6LDOIBU7.js +0 -9
  175. package/dist/bin/chunks/chunk-AI7JUA46.js +0 -13
  176. package/dist/bin/chunks/chunk-GQKQEK5N.js +0 -11
  177. package/dist/bin/chunks/chunk-JQM3DKCH.js +0 -12
  178. package/dist/bin/chunks/chunk-OLEQNRKX.js +0 -8
  179. package/dist/bin/chunks/chunk-PPVF2N6C.js +0 -3
  180. package/dist/bin/chunks/chunk-WEHA3JFD.js +0 -3
  181. package/dist/bin/chunks/chunk-YQEKKZTU.js +0 -12
  182. package/dist/bin/chunks/cp-OMVKM35F.js +0 -3
  183. package/dist/bin/chunks/du-LUFPVLNW.js +0 -3
  184. package/dist/bin/chunks/find-AWH2KOY7.js +0 -3
  185. package/dist/bin/chunks/gzip-FDPA6EKG.js +0 -3
  186. package/dist/bin/chunks/ln-B35EKC2Q.js +0 -3
  187. package/dist/bin/chunks/ls-Q6ZZ6SQ2.js +0 -3
  188. package/dist/bin/chunks/mkdir-74BP5NTG.js +0 -3
  189. package/dist/bin/chunks/mv-76LAHXFR.js +0 -3
  190. package/dist/bin/chunks/readlink-EHXJNW62.js +0 -3
  191. package/dist/bin/chunks/rg-PXNKNIMY.js +0 -3
  192. package/dist/bin/chunks/rm-TF2NJQIA.js +0 -3
  193. package/dist/bin/chunks/rmdir-7ZIVFZJX.js +0 -3
  194. package/dist/bin/chunks/split-ZNNNHKSP.js +0 -3
  195. package/dist/bin/chunks/sqlite3-KP42NNIY.js +0 -3
  196. package/dist/bin/shell/chunks/chmod-WYYTXGVB.js +0 -3
  197. package/dist/bin/shell/chunks/chunk-43E7AR6A.js +0 -3
  198. package/dist/bin/shell/chunks/chunk-6LDOIBU7.js +0 -9
  199. package/dist/bin/shell/chunks/chunk-AI7JUA46.js +0 -13
  200. package/dist/bin/shell/chunks/chunk-GQKQEK5N.js +0 -11
  201. package/dist/bin/shell/chunks/chunk-JQM3DKCH.js +0 -12
  202. package/dist/bin/shell/chunks/chunk-OLEQNRKX.js +0 -8
  203. package/dist/bin/shell/chunks/chunk-PPVF2N6C.js +0 -3
  204. package/dist/bin/shell/chunks/chunk-WEHA3JFD.js +0 -3
  205. package/dist/bin/shell/chunks/chunk-YQEKKZTU.js +0 -12
  206. package/dist/bin/shell/chunks/cp-OMVKM35F.js +0 -3
  207. package/dist/bin/shell/chunks/du-LUFPVLNW.js +0 -3
  208. package/dist/bin/shell/chunks/find-AWH2KOY7.js +0 -3
  209. package/dist/bin/shell/chunks/gzip-FDPA6EKG.js +0 -3
  210. package/dist/bin/shell/chunks/ln-B35EKC2Q.js +0 -3
  211. package/dist/bin/shell/chunks/ls-Q6ZZ6SQ2.js +0 -3
  212. package/dist/bin/shell/chunks/mkdir-74BP5NTG.js +0 -3
  213. package/dist/bin/shell/chunks/mv-76LAHXFR.js +0 -3
  214. package/dist/bin/shell/chunks/readlink-EHXJNW62.js +0 -3
  215. package/dist/bin/shell/chunks/rg-PXNKNIMY.js +0 -3
  216. package/dist/bin/shell/chunks/rm-TF2NJQIA.js +0 -3
  217. package/dist/bin/shell/chunks/rmdir-7ZIVFZJX.js +0 -3
  218. package/dist/bin/shell/chunks/split-ZNNNHKSP.js +0 -3
  219. package/dist/bin/shell/chunks/sqlite3-KP42NNIY.js +0 -3
  220. package/dist/bundle/chunks/chmod-WM2JFFQC.js +0 -2
  221. package/dist/bundle/chunks/chunk-7IJWBG4I.js +0 -2
  222. package/dist/bundle/chunks/chunk-MLIO3BK2.js +0 -7
  223. package/dist/bundle/chunks/chunk-PIRTX3D3.js +0 -8
  224. package/dist/bundle/chunks/chunk-TBVD66LC.js +0 -10
  225. package/dist/bundle/chunks/chunk-W2Z6LYL6.js +0 -11
  226. package/dist/bundle/chunks/chunk-WN54B5NQ.js +0 -12
  227. package/dist/bundle/chunks/chunk-WXPNKIIH.js +0 -2
  228. package/dist/bundle/chunks/chunk-YJKHREBZ.js +0 -11
  229. package/dist/bundle/chunks/chunk-YUSFCOM7.js +0 -2
  230. package/dist/bundle/chunks/cp-2KZIPZJS.js +0 -2
  231. package/dist/bundle/chunks/du-7AZCLKR6.js +0 -2
  232. package/dist/bundle/chunks/find-END3EAHV.js +0 -2
  233. package/dist/bundle/chunks/gzip-RQOBR22H.js +0 -2
  234. package/dist/bundle/chunks/ln-OPY2ZVGQ.js +0 -2
  235. package/dist/bundle/chunks/ls-ZPXGZX63.js +0 -2
  236. package/dist/bundle/chunks/mkdir-WDDKK2P3.js +0 -2
  237. package/dist/bundle/chunks/mv-ZF6UBVRB.js +0 -2
  238. package/dist/bundle/chunks/readlink-U5OM5A3M.js +0 -2
  239. package/dist/bundle/chunks/rg-NAMXBYKS.js +0 -2
  240. package/dist/bundle/chunks/rm-OAZOF7XI.js +0 -2
  241. package/dist/bundle/chunks/rmdir-YJKPQVCK.js +0 -2
  242. package/dist/bundle/chunks/split-JICLAMP6.js +0 -2
  243. package/dist/bundle/chunks/sqlite3-4EZ4GXVD.js +0 -2
package/CHANGELOG.md CHANGED
@@ -1,316 +1,349 @@
1
- # just-bash
2
-
3
- ## 3.6.0
4
-
5
- ### Minor Changes
6
-
7
- - [`942abb1`](https://github.com/JerryAZR/just-bash/commit/942abb1a41b836757d98a7a47c9c85633b0455ad) Thanks [@JerryAZR](https://github.com/JerryAZR)! - `rm -f` now suppresses only ENOENT errors, matching GNU rm: mount-point (EBUSY) and other failures are reported and exit 1 instead of being silently swallowed. Previously `rm -rf` on a mount point or its parent was a silent no-op with exit 0, while the change set correctly showed nothing had been deleted.
8
-
9
- `AgentSandbox` gains path conversion helpers: `resolveRealPath(realPath)` maps a real host path to `{ mountPoint, overlay, path }` for direct shadow inspection on the overlay, and `toRealPath(vfsPath)` maps a VFS path to its real host path. Both return null for paths outside the mounted overlays.
10
-
11
- ## 3.4.2
12
-
13
- ### Patch Changes
14
-
15
- - [#381](https://github.com/vercel-labs/just-bash/pull/381) [`d40a42d`](https://github.com/vercel-labs/just-bash/commit/d40a42d514b22da4ed023635d747c8b3f029a6c5) Thanks [@cramforce](https://github.com/cramforce)! - Include the security and transform declaration trees referenced by the package entrypoints and worker declarations in published packages.
16
-
17
- ## 3.4.1
18
-
19
- ### Patch Changes
20
-
21
- - [#373](https://github.com/vercel-labs/just-bash/pull/373) [`2c1831c`](https://github.com/vercel-labs/just-bash/commit/2c1831cc832d4b09ee4e1823526afb6ccca77942) Thanks [@cramforce](https://github.com/cramforce)! - Prevent defense-in-depth violation reporting from recursively overflowing the call stack in host runtimes that wrap `Date.now()`, honor configured main-thread violation exclusions, include actionable exclusion guidance for configurable violations, and keep constructor-execution protections non-excludable.
22
-
23
- ## 3.4.0
24
-
25
- ### Minor Changes
26
-
27
- - [#303](https://github.com/vercel-labs/just-bash/pull/303) [`c5a2a4a`](https://github.com/vercel-labs/just-bash/commit/c5a2a4a35c7490276befa716acae3fe880c1fe89) Thanks [@boramuyar](https://github.com/boramuyar)! - Provide the shadowed bundled command to custom command overrides through `CommandContext.origCommand`.
28
-
29
- ## 3.3.0
30
-
31
- ### Minor Changes
32
-
33
- - [#291](https://github.com/vercel-labs/just-bash/pull/291) [`47f604a`](https://github.com/vercel-labs/just-bash/commit/47f604a7f1e12730318e4c88c7872a5a35383056) Thanks [@trieloff](https://github.com/trieloff)! - jq: add external-argument flags (`--arg`, `--argjson`, `--rawfile`, `--slurpfile`, `--args`, `--jsonargs`) and the `$ARGS` object (`$ARGS.named` / `$ARGS.positional`), matching real jq 1.7.1 behavior including exit codes, error messages, and prototype-sensitive key handling.
34
-
35
- - [#336](https://github.com/vercel-labs/just-bash/pull/336) [`d97425d`](https://github.com/vercel-labs/just-bash/commit/d97425dff8f51cfd773d22bc009561a09235cd1b) Thanks [@trieloff](https://github.com/trieloff)! - Support user file descriptors (fd >= 3). `exec 3< file`, `N< file` / `N> file` / `N>> file` on any command, `read -u N`, `read <&N`, `>&N`, `N<&M`, and `N<&-` now go through a real descriptor table: a descriptor carries one shared read position, `exec` keeps it open until it is closed, and every other construct — including `done N< file` on a loop — gets it only for the duration of that command.
36
-
37
- - [#331](https://github.com/vercel-labs/just-bash/pull/331) [`6680247`](https://github.com/vercel-labs/just-bash/commit/66802470837cfac3a58a09e00d37b2070387ba7b) Thanks [@trieloff](https://github.com/trieloff)! - Treat a `-` FILE operand in `grep` as standard input, matching GNU. `grep PATTERN -` now reads stdin instead of failing with "No such file or directory", stdin is labelled `(standard input)` in the multi-file prefix and in `-l`/`-L`/`-c` output, repeated `-` operands see the stream drained by the first one, and `-` is exempt from `-r` recursion and `--include`/`--exclude` filtering.
38
-
39
- - [#325](https://github.com/vercel-labs/just-bash/pull/325) [`edc7f2f`](https://github.com/vercel-labs/just-bash/commit/edc7f2fac5337cebd19911c5756b76ed02e52090) Thanks [@trieloff](https://github.com/trieloff)! - Support process substitution `<(cmd)` and `>(cmd)`.
40
-
41
- `<(cmd)` runs `cmd` and substitutes a readable `/dev/fd/N` path backed by an
42
- in-memory file; `>(cmd)` substitutes a writable path whose contents are fed to
43
- `cmd` once the outer command finishes. Descriptors are numbered from 63
44
- downwards like bash and released when the command that opened them completes.
45
- Process substitutions retain their surrounding word context in assignments,
46
- conditionals, regular expressions, and heredoc delimiters. Previously any use
47
- raised `Parse error: Expected redirection target`.
48
-
49
- - [#327](https://github.com/vercel-labs/just-bash/pull/327) [`eaedb5b`](https://github.com/vercel-labs/just-bash/commit/eaedb5bc34cffd2077b88bb1ccc48ea7e0545a48) Thanks [@trieloff](https://github.com/trieloff)! - Add `grep -f FILE` / `--file=FILE` to read patterns from a file (one per line). Patterns from `-f` OR-combine with `-e` patterns and with each other, `-f -` reads patterns from stdin, empty pattern lines match every line, and an empty pattern file selects nothing (exit 1). Newline-separated `PATTERNS` operands are now split into individual patterns, and `-x` groups alternatives correctly (`^(?:a|b)$`).
50
-
51
- ### Patch Changes
52
-
53
- - [#358](https://github.com/vercel-labs/just-bash/pull/358) [`bd1df37`](https://github.com/vercel-labs/just-bash/commit/bd1df37f8ff836355f470e95dcaa004b769d1e61) Thanks [@privatenumber](https://github.com/privatenumber)! - Parse and serialize bare file descriptor variable redirections such as `{output}>output.log` and `{input}<<EOF`. Bare redirects create their target with a command-scoped descriptor, while named command forms keep the allocated descriptor available.
54
-
55
- - [#347](https://github.com/vercel-labs/just-bash/pull/347) [`abb904b`](https://github.com/vercel-labs/just-bash/commit/abb904b1e126d14aa437b05f006df83117f06db3) Thanks [@privatenumber](https://github.com/privatenumber)! - Fix escaped reserved words being parsed as shell syntax. Unquoted escapes now retain their provenance through lexing and word parsing, including when the word is serialized back to Bash.
56
-
57
- - [#332](https://github.com/vercel-labs/just-bash/pull/332) [`4f9bdec`](https://github.com/vercel-labs/just-bash/commit/4f9bdec02edb9eb72511546b759cb7e20bc2e27e) Thanks [@trieloff](https://github.com/trieloff)! - Fix `grep -L` exit status to match GNU grep. The status reports whether a line
58
- was selected, not whether a filename was printed, so `grep -L` now exits 0 when
59
- every file matched (printing nothing) and 1 when no file matched (printing every
60
- name) — previously these were inverted.
61
-
62
- - [#339](https://github.com/vercel-labs/just-bash/pull/339) [`31d247f`](https://github.com/vercel-labs/just-bash/commit/31d247fe3a62f081b4462064da195552ab0a421c) Thanks [@mutewinter](https://github.com/mutewinter)! - network: restore private-range-enforced requests from the bundled build
63
-
64
- Every request made with `denyPrivateRanges` enabled failed with `Network access denied: DNS pinning unavailable for private IP enforcement`, so `curl` could not reach any host at all. The published ESM bundle was affected; source consumers and the CommonJS bundle were not.
65
-
66
- The pinned connection owner reads `Agent` and `fetch` off a dynamic `import("undici")`. Node's resolution of the package exposes those as named exports, but the ESM build inlines undici's CommonJS module into a chunk whose namespace carries it under `default` alone, so `Agent` was `undefined` and the `TypeError` from constructing it was reported as a runtime incapable of pinning.
67
-
68
- The namespace is now normalized before the transport is read off it, which also covers a consumer that bundles just-bash further.
69
-
70
- - [#336](https://github.com/vercel-labs/just-bash/pull/336) [`d97425d`](https://github.com/vercel-labs/just-bash/commit/d97425dff8f51cfd773d22bc009561a09235cd1b) Thanks [@trieloff](https://github.com/trieloff)! - Stop command groups, function bodies and `eval` from rewinding stdin they never replaced, so `{ { read a; }; read b; }` gives `b` the second line instead of replaying the first.
71
-
72
- - [#348](https://github.com/vercel-labs/just-bash/pull/348) [`1a7940d`](https://github.com/vercel-labs/just-bash/commit/1a7940ddf91dec8f69125474a40cef1adebabee9) Thanks [@privatenumber](https://github.com/privatenumber)! - Reject unsupported command-leading reserved words in every parser context instead of discarding them or executing them as simple commands. Unknown command AST nodes now fail explicitly instead of returning a successful result.
73
-
74
- - [#345](https://github.com/vercel-labs/just-bash/pull/345) [`2208a34`](https://github.com/vercel-labs/just-bash/commit/2208a34e27d33a2fce712fbd024875ec60747553) Thanks [@privatenumber](https://github.com/privatenumber)! - Restore command groups and subshells after the process-substitution and stdin-ownership changes were combined without forwarding ownership through inner command dispatch.
75
-
76
- - [#336](https://github.com/vercel-labs/just-bash/pull/336) [`d97425d`](https://github.com/vercel-labs/just-bash/commit/d97425dff8f51cfd773d22bc009561a09235cd1b) Thanks [@trieloff](https://github.com/trieloff)! - Apply output redirections attached to `while` and `until` loops. `while true; do echo x; break; done >/dev/null` no longer leaks its output to the caller, and `> file`, `>>`, `2>`, `2>&1`, `&>` and `>|` now behave on loops the way they already did on `for` and `case`. `until` loops also gained the input-redirection handling `while` loops already had, so `until ! read l; do ...; done < file` reads from the file. A loop now only restores stdin it owns, so reading inside a loop no longer rewinds an enclosing group's read position: `printf 'a\nb\n' | { while read x; do break; done; read y; }` sees `y=b`.
77
-
78
- - [#328](https://github.com/vercel-labs/just-bash/pull/328) [`65dafd5`](https://github.com/vercel-labs/just-bash/commit/65dafd55afbfa7e62642ce485787f7d65fad4961) Thanks [@trieloff](https://github.com/trieloff)! - Stop pipelines from draining the enclosing shell's stdin, so `while read …; do … | …; done < file` runs once per line again.
79
-
80
- - [#349](https://github.com/vercel-labs/just-bash/pull/349) [`be55fec`](https://github.com/vercel-labs/just-bash/commit/be55fec4e23b3f5a42cf8eaeb6939b379f741ae1) Thanks [@privatenumber](https://github.com/privatenumber)! - Process redirections through policy-driven transactions that preserve Bash ordering, descriptor lifetimes, persistent `exec` routes, compound-command stdin, control-flow output routing, and shared read-write descriptor positions without duplicate expansion or opening.
81
-
82
- - [#368](https://github.com/vercel-labs/just-bash/pull/368) [`3ee215c`](https://github.com/vercel-labs/just-bash/commit/3ee215c2ad56c96ce0d88e2813050df9f15afa38) Thanks [@cramforce](https://github.com/cramforce)! - FS sym-link hardening
83
-
84
- - [#338](https://github.com/vercel-labs/just-bash/pull/338) [`19a02c2`](https://github.com/vercel-labs/just-bash/commit/19a02c297d110fde8a8a3376d6956c2c549d128e) Thanks [@mutewinter](https://github.com/mutewinter)! - sqlite3: report failed statements on stderr and exit non-zero without `-bail`
85
-
86
- A statement that failed was written to **stdout** as `Error: ...` and the command still exited `0` unless `-bail` was passed. Real `sqlite3` writes the error to stderr and exits `1` in either mode; `-bail` only decides whether the remaining statements still run.
87
-
88
- Two consequences for callers: `sqlite3 db "SELECT ..." > out.csv` silently wrote the error text into the data file, and `sqlite3 db "..." && next-step` ran `next-step` after the query had failed, so a shell script could not detect a bad query without opting into `-bail` and losing the ability to see later statements.
89
-
90
- Errors now accumulate on stderr in statement order and the exit status is `1` whenever any statement failed. Successful runs are unchanged, `-bail` still stops at the first failure, and the partial stdout produced before a failure is still emitted. Writeback of a partially-successful script is also unchanged.
91
-
92
- - [#360](https://github.com/vercel-labs/just-bash/pull/360) [`1fbde34`](https://github.com/vercel-labs/just-bash/commit/1fbde341d74ff7f933d9cead9a390a6ab65b5df3) Thanks [@privatenumber](https://github.com/privatenumber)! - Preserve whether a here-document ended at its delimiter or at end-of-input. Unterminated final body lines now receive Bash's trailing newline, backslash-newline continuations are removed during expansion, and serialization rejects unterminated documents rather than manufacturing a closing delimiter.
93
-
94
- ## 3.2.0
95
-
96
- ### Minor Changes
97
-
98
- - [#304](https://github.com/vercel-labs/just-bash/pull/304) [`3d39a71`](https://github.com/vercel-labs/just-bash/commit/3d39a714b3751cedc173dffae27933dfe7b8b3b5) Thanks [@subsetpark](https://github.com/subsetpark)! - Add curl `-G`/`--get` query-string data handling and preserve command-line order when repeated `-d`, `--data-raw`, `--data-binary`, and `--data-urlencode` options are mixed, including `@file` forms. Data requests now also set curl's standard `application/x-www-form-urlencoded` content type unless the caller supplies one.
99
-
100
- - [#307](https://github.com/vercel-labs/just-bash/pull/307) [`7c4caed`](https://github.com/vercel-labs/just-bash/commit/7c4caedf02599628f19b243f960d480760f5e476) Thanks [@cramforce](https://github.com/cramforce)! - Harden untrusted execution with shared aggregate budgets, liberal normal and
101
- opt-in hardened limit profiles, request-bound network validation, bounded
102
- archive and worker processing, transactional filesystem and shell state, and
103
- expanded adversarial regression checks.
104
-
105
- Established command declarations and host-extension defaults remain source
106
- compatible. Dispatched callbacks receive a `ResolvedCommandContext` with
107
- required limits; applications can use `createCommandContext({ fs })` for direct
108
- invocation, opt into restricted custom-command execution with `trusted: false`,
109
- and select tighter resource policy with the `hardened` profile. All
110
- host-registration paths keep their established trusted default. The supported
111
- Node.js floor is now declared as `>=20.18.1`.
112
-
113
- ### Patch Changes
114
-
115
- - [#315](https://github.com/vercel-labs/just-bash/pull/315) [`6df692f`](https://github.com/vercel-labs/just-bash/commit/6df692f236ca108c888552a67557998156ac845b) Thanks [@matchai](https://github.com/matchai)! - Treat `--` as the end of options in `grep`.
116
-
117
- ## 3.1.0
118
-
119
- ### Minor Changes
120
-
121
- - [#284](https://github.com/vercel-labs/just-bash/pull/284) [`af2e0f4`](https://github.com/vercel-labs/just-bash/commit/af2e0f4cdeb5417ea59e25140038c239dd8fd92d) Thanks [@arimxyer](https://github.com/arimxyer)! - sandbox: forward capability flags from `SandboxOptions` into the underlying `Bash`
122
-
123
- `Sandbox.create(opts)` previously constructed its internal `Bash` with only a subset
124
- of `BashOptions`, silently dropping the optional capability flags (`python`,
125
- `javascript`, `commands`, `customCommands`, `fetch`). A host that drives just-bash
126
- through the `Sandbox` API (rather than `new Bash(...)`) therefore could not enable
127
- python3, js-exec, a restricted command set, custom commands, or a custom fetch — even
128
- though the runtimes ship in the package.
129
-
130
- `SandboxOptions` now exposes those fields and `Sandbox.create` forwards them into the
131
- `Bash` it builds. Behavior is unchanged when a caller omits them (each falls back to
132
- its existing `BashOptions` default — Python/js-exec stay off, the full command set
133
- stays available). Fixes the root cause behind vercel/eve#431.
134
-
135
- ### Patch Changes
136
-
137
- - [#268](https://github.com/vercel-labs/just-bash/pull/268) [`7a5a0b9`](https://github.com/vercel-labs/just-bash/commit/7a5a0b9ae3bf0524722653cbf4b45e6bc176cf22) Thanks [@trieloff](https://github.com/trieloff)! - jq: allow nested double-quoted strings inside `"\(...)"` string interpolation
138
-
139
- jq string interpolation of the form `"\(...)"` that contained a nested double-quoted string — for example `"\(sub("T.*";""))"` or `"\(ltrimstr("ab"))"` — previously failed with a parse error. The tokenizer terminated the outer string at the first `"` it saw inside the interpolation expression, so the rest of the expression became orphaned tokens.
140
-
141
- The lexer now tracks `\(...)` depth while consuming a string literal and treats nested `"..."` pairs as opaque content while inside an interpolation, restoring them verbatim into the captured interpolation source. `parseStringInterpolation` similarly skips over nested strings when balancing parentheses, so the interpolation expression is captured as a whole and handed to the expression parser intact.
142
-
143
- ## 3.0.3
144
-
145
- ### Patch Changes
146
-
147
- - [#277](https://github.com/vercel-labs/just-bash/pull/277) [`aec5643`](https://github.com/vercel-labs/just-bash/commit/aec56431d7d9b6fcb141bbfe25d26f4931f54f80) Thanks [@mutewinter](https://github.com/mutewinter)! - interpreter: avoid lazy import in variable assignment path that trips defense-in-depth (fixes [#273](https://github.com/vercel-labs/just-bash/issues/273))
148
-
149
- Any non-`export` variable assignment (bare `SECRET=s`, prefixed `SECRET=s cmd`,
150
- or before a custom command) failed with a defense-in-depth security violation
151
- (`dynamic import of Node.js builtin 'node:module' is blocked during script
152
- execution`), while plain commands and `export`-ed assignments passed.
153
-
154
- `processScalarAssignment()` resolved `isArray` via `await import("./expansion.js")`
155
- in two spots. In the bundled `dist`, that dynamic `import()` marks `expansion.js`
156
- as a lazily-linked chunk whose `createRequire` banner imports `node:module`; the
157
- defense layer's ESM `resolve` hook blocks that builtin import when the sandbox is
158
- active and untrusted, so it blocked just-bash's own chunk load. The file already
159
- statically imports from `./expansion.js`, so `isArray` is now pulled from that
160
- static import and the two lazy imports are removed — no lazy `node:module`-bearing
161
- chunk is linked at runtime. No public API change.
162
-
163
- - [#276](https://github.com/vercel-labs/just-bash/pull/276) [`1ec5eec`](https://github.com/vercel-labs/just-bash/commit/1ec5eec0aefd099d23ac9f056df1e6612c81d49b) Thanks [@mutewinter](https://github.com/mutewinter)! - interpreter: preserve leading whitespace in multi-line quoted strings (fixes [#259](https://github.com/vercel-labs/just-bash/issues/259))
164
-
165
- `exec()` runs each script through `normalizeScript()`, which `trimStart()`s
166
- leading indentation from lines so indented template-literal scripts parse. It
167
- was applied line-by-line and stripped the leading whitespace inside multi-line
168
- single- and double-quoted strings too. The visible symptom was `python3 -c
169
- '...'` (and `node -e`, `awk`, etc.) with an indented body failing with
170
- `IndentationError`, while the same code via heredoc or pipe worked.
171
-
172
- `normalizeScript()` is now quote-aware (mirroring the earlier heredoc-aware
173
- fix): it only strips indentation from lines that begin outside any quote, and
174
- preserves lines that begin inside an unterminated single- or double-quoted
175
- string verbatim. This also un-skips four sed spec tests whose indented stdin
176
- was previously being corrupted.
177
-
178
- - [#286](https://github.com/vercel-labs/just-bash/pull/286) [`cb2b583`](https://github.com/vercel-labs/just-bash/commit/cb2b583b3f46e6bb4e6982c4bfe19903ec811a87) Thanks [@privatenumber](https://github.com/privatenumber)! - interpreter: deliver redirected output to each fd's final target (fixes `cmd > file 2>&1` leaking stderr to stdout)
179
-
180
- `applyRedirections()` processed a command's redirection list sequentially over
181
- the result's stdout/stderr strings, moving content at each step. The
182
- duplication operators (`2>&1`, `1>&2`) merged into the live stream regardless
183
- of where the source fd pointed, so the canonical `cmd > file 2>&1` wrote
184
- stdout to the file but leaked stderr onto the caller's stdout — including
185
- "command not found" errors and custom-command stderr. Any wrapper protocol
186
- that parses the enclosing script's stdout (e.g. a runner emitting a JSON
187
- payload after `eval "$CMD" > "$OUT" 2>&1`) saw the leaked stderr corrupt its
188
- stream. Ordering variants were wrong in other ways: `cmd 2>&1 > file` put
189
- stderr in the file instead of on stdout, and `cmd > a > b` wrote content to
190
- `a` instead of `b`.
191
-
192
- The pass now mirrors how bash sets up fds before running the command: each
193
- output redirection only opens/truncates its target and re-points the fd's
194
- sink (file, /dev/null, or a snapshot of the caller-visible stream), and
195
- duplication operators copy the source fd's current sink. Stream content is
196
- delivered once, after the whole list is processed, to each fd's final sink.
197
- This makes `cmd > file 2>&1` send stderr to the file, `cmd 2>&1 > file` keep
198
- stderr on the caller's stdout, `cmd > all 2>&1 2> err` let the later `2> err`
199
- reclaim stderr, and `cmd > a > b` truncate `a` while writing content to `b`.
200
- The `/dev/null`-as-regular-VFS-file behavior for stdout redirects is
201
- preserved.
202
-
203
- ## 3.0.2
204
-
205
- ### Patch Changes
206
-
207
- - [#272](https://github.com/vercel-labs/just-bash/pull/272) [`150a915`](https://github.com/vercel-labs/just-bash/commit/150a915a1d45a2cc7f2b6aec3268f27116c34916) Thanks [@trieloff](https://github.com/trieloff)! - interpreter: fix UTF-8 mojibake when a script interleaves text-output and byte-output statements
208
-
209
- A single `exec()` can interleave text-shaped statements (sed, awk, echo — `ö`
210
- as `U+00F6`) with byte-shaped ones (grep | head, cat — `ö` as bytes
211
- `0xC3 0xB6`). `executeScript` / `executeStatement` concatenated each result's
212
- raw stdout, so the lone high byte from the text half made the combined stream
213
- invalid UTF-8, the output-boundary decoder bailed, and the byte half came back
214
- as Latin-1 mojibake (`Köpenicker` for `Köpenicker`). The same path backs
215
- command substitution, so `echo "你好: $(cat /file)"` was affected too.
216
-
217
- The fix decodes each statement/pipeline result to text via its explicit
218
- `stdoutKind` (`decodedTextFromResult`) before concatenating — no guessing from
219
- string contents, so text whose code units merely look like UTF-8 (`ö`) is
220
- preserved. `tac` (stdin path) and `curl` (response body) now declare
221
- `stdoutKind: "bytes"` on the results that forward raw bytes, so the decode is
222
- driven per output rather than by inspecting characters.
223
-
224
- - [#256](https://github.com/vercel-labs/just-bash/pull/256) [`75d8dfd`](https://github.com/vercel-labs/just-bash/commit/75d8dfd3a322786250e3b0f81b1500c87610acb7) Thanks [@Hazzng](https://github.com/Hazzng)! - js-exec: fix Buffer shim correctness — ascii encode now uses & 0xff (not & 0x7f), consolidate latin1/ascii into shared \_rawEncode, fix Buffer.from(ArrayBuffer, offset, length), throw on invalid byteLength input, clamp negative toString start, throw RangeError for out-of-range write offset
225
-
226
- - [#239](https://github.com/vercel-labs/just-bash/pull/239) [`1369b77`](https://github.com/vercel-labs/just-bash/commit/1369b772fe887694c09ce834d1b0b21aa6420b59) Thanks [@trieloff](https://github.com/trieloff)! - curl: interpret `@file` for `-d`/`--data`, `--data-binary`, and `--data-urlencode`
227
-
228
- Real curl reads file contents when these flags are passed `@filename`:
229
-
230
- - `-d @file` / `--data @file` — read file contents, strip CR/LF.
231
- - `--data-binary @file` — read file contents verbatim (newlines preserved).
232
- - `--data-urlencode @file` — read file, URL-encode the contents.
233
- - `--data-urlencode name@file` — prefix the URL-encoded contents with `name=`.
234
-
235
- just-bash's curl previously passed `@filename` through verbatim as the HTTP body. Posting JSON or any non-trivial payload via `curl --data-binary @payload.json https://…` sent the literal string `@payload.json` instead of the file. The new behavior matches upstream curl; `--data-raw` keeps the documented "no `@` interpretation" semantics.
236
-
237
- - [#262](https://github.com/vercel-labs/just-bash/pull/262) [`4ece258`](https://github.com/vercel-labs/just-bash/commit/4ece2580d8cb707e6c6b7fa22897ea3fdd21739a) Thanks [@chernetsov](https://github.com/chernetsov)! - parser: don't treat quotes inside a heredoc body as shell quotes when finding the end of a command substitution
238
-
239
- A command substitution whose body contained a heredoc with an unbalanced quote in its body — most commonly an apostrophe in literal prose, e.g. `June's` — failed to parse with `bash: syntax error: ... unexpected EOF while looking for matching ')'`:
240
-
241
- ```bash
242
- OUT=$(cat <<'SCRIPT'
243
- June's moon
244
- SCRIPT
245
- )
246
- ```
247
-
248
- Both the lexer's `$(...)` word scanner and the substitution boundary scanner walked into the heredoc body and applied shell quote tracking to it. The `'` in `June's` opened a single-quoted string that never closed, so the closing `)` was swallowed and the scan ran to EOF. In bash a heredoc body is literal text and must be skipped wholesale when locating the substitution boundary.
249
-
250
- Both scanners are now heredoc-aware: when scanning a `$(...)` they recognize `<<` / `<<-` operators (but not the `<<<` here-string), capture the possibly-quoted delimiter, and skip the heredoc body lines literally — without quote or paren tracking — up to the terminator. Multiple heredocs on one line and tab-stripping (`<<-`) are handled. This fixes the common pattern of capturing the output of a connector/CLI invocation that is fed a heredoc script containing apostrophes, backticks, or parentheses.
251
-
252
- The heredoc scan also tracks arithmetic `((...))` nesting so a `<<` left-shift inside `$((...))` (or a nested arithmetic expansion) is not mistaken for a heredoc opener — previously a multi-line arithmetic expansion containing a shift, e.g. `$((\n1 << 2\n))`, had its closing `))` swallowed by spurious body-skipping.
253
-
254
- - [#248](https://github.com/vercel-labs/just-bash/pull/248) [`d64009a`](https://github.com/vercel-labs/just-bash/commit/d64009aef6bc1556e7c84b22ed455863275ea953) Thanks [@Hazzng](https://github.com/Hazzng)! - perf(grep): up to 14.5× speedup via preFilter extensions and matcher reuse.
255
-
256
- Anchored alternation patterns like `^def \|^async def` now extract literal needles (stripping outer `^`/`$`), enabling the `String.indexOf` fast-path. Files with no matching needle are rejected before `split("\n")`, skipping RE2 entirely. `acquireMatcher()` extended to `match()`, `replace()`, `search()`, and `matchAll()` to reduce GC pressure across awk/sed hot-paths.
257
-
258
- - [#261](https://github.com/vercel-labs/just-bash/pull/261) [`c9904de`](https://github.com/vercel-labs/just-bash/commit/c9904dea24ad2aa847749ee6289239c2a2c651fc) Thanks [@chernetsov](https://github.com/chernetsov)! - set: support a bundled `-o`/`+o` long option inside a short-flag cluster (e.g. `set -euo pipefail`)
259
-
260
- The `set` builtin previously rejected `set -euo pipefail` with `bash: set: -o: invalid option`, because it parsed each character after the `-` as an independent short flag and has no `o` short flag. `-o` was only honored as its own token (`set -eu -o pipefail`).
261
-
262
- This is the canonical "bash strict mode" idiom and is extremely common in generated scripts, so the whole script would abort on its first line.
263
-
264
- `set` now matches bash: an `o` inside a cluster consumes the _next word_ as its long-option name, and the remaining characters keep being parsed as short flags. So `set -euo pipefail` is equivalent to `set -e -u -o pipefail`, `set -oe pipefail` enables both `pipefail` and `errexit`, trailing words become positional parameters, and `+`-clusters (`set +euo pipefail`) disable the options. An invalid bundled name (`set -euo bogus`) still reports `invalid option name`, and an `o` with no following argument falls back to the standalone `-o`/`+o` listing.
265
-
266
- ## 3.0.1
267
-
268
- ### Patch Changes
269
-
270
- - [#238](https://github.com/vercel-labs/just-bash/pull/238) [`01a4721`](https://github.com/vercel-labs/just-bash/commit/01a4721324350adea4b035b311f0b60ccdbb65ff) Thanks [@cramforce](https://github.com/cramforce)! - Fix `Dynamic require of "tty" is not supported` crash when invoking commands that transitively load `debug` / `supports-color` (notably `file`) under ESM Node consumers and via the `just-bash` CLI binary.
271
-
272
- The esbuild dynamic-require shim emitted into the ESM Node bundles had no `require` to delegate to at chunk-init under ESM, so any runtime `require("tty")` / `require("os")` from `file-type` → `debug` chain threw. Build banners now provide `createRequire(import.meta.url)` for `build:lib`, `build:cli`, and `build:shell`. CJS and browser bundles are unchanged.
273
-
274
- Fixes [#211](https://github.com/vercel-labs/just-bash/issues/211).
275
-
276
- ## 3.0.0
277
-
278
- ### Major Changes
279
-
280
- - [#233](https://github.com/vercel-labs/just-bash/pull/233) [`7cca738`](https://github.com/vercel-labs/just-bash/commit/7cca73831987e3331160f426b7a66d7217b8cf79) Thanks [@cramforce](https://github.com/cramforce)! - Breaking change for stdin byte/utf8-handling. Will break some custom commands that handle stdin
281
-
282
- ### Minor Changes
283
-
284
- - [#209](https://github.com/vercel-labs/just-bash/pull/209) [`b3bd85e`](https://github.com/vercel-labs/just-bash/commit/b3bd85ed816445e6d148290163a1900f49ebea82) Thanks [@cramforce](https://github.com/cramforce)! - Introducing plumbing for integrating executor and adding a peer package for the implememtation
285
-
286
- - [#233](https://github.com/vercel-labs/just-bash/pull/233) [`7cca738`](https://github.com/vercel-labs/just-bash/commit/7cca73831987e3331160f426b7a66d7217b8cf79) Thanks [@cramforce](https://github.com/cramforce)! - TS-enforced correct handling of utf8 on stdin. Impacts many commands
287
-
288
- ## 2.14.5
289
-
290
- ### Patch Changes
291
-
292
- - [#214](https://github.com/vercel-labs/just-bash/pull/214) [`da58f4f`](https://github.com/vercel-labs/just-bash/commit/da58f4f523c5e9c1c444106a0f2a7777a59fb618) Thanks [@subsetpark](https://github.com/subsetpark)! - jq: accept control characters inside JSON strings
293
-
294
- - [#221](https://github.com/vercel-labs/just-bash/pull/221) [`a835686`](https://github.com/vercel-labs/just-bash/commit/a835686c97f5cac2e5b94bd551d996079a33dfc2) Thanks [@cramforce](https://github.com/cramforce)! - upgrade deps
295
-
296
- - [#218](https://github.com/vercel-labs/just-bash/pull/218) [`13d78b2`](https://github.com/vercel-labs/just-bash/commit/13d78b2876d7ac7b6bc3a6eacfa3937bbb79665f) Thanks [@Hazzng](https://github.com/Hazzng)! - grep: 5-123x faster pattern matching via RE2 matcher reuse and literal pre-filter
297
-
298
- ## 2.14.4
299
-
300
- ### Patch Changes
301
-
302
- - [#206](https://github.com/vercel-labs/just-bash/pull/206) [`6ccc35f`](https://github.com/vercel-labs/just-bash/commit/6ccc35f5a9b5c6f395b145ed2ec7ee71c4862057) Thanks [@subsetpark](https://github.com/subsetpark)! - Fix awk lexer to honor POSIX statement continuation across newlines after `,`,
303
- `{`, `&&`, `||`, `?`, `:`, `do`, `else`, `if`, and `while`. Previously, a
304
- multi-line idiom like `printf "%s=%d\n", \n $1, $2` (comma at end-of-line
305
- followed by indented args on the next line) failed with `Unexpected token:
306
- NEWLINE` because the lexer emitted a NEWLINE token unconditionally. The
307
- lexer now suppresses the NEWLINE when it immediately follows one of the
308
- continuation-allowing tokens, matching POSIX awk.
309
-
310
- - [#212](https://github.com/vercel-labs/just-bash/pull/212) [`733c847`](https://github.com/vercel-labs/just-bash/commit/733c84796e3abbd05a25cf67805bf4b030d0b02d) Thanks [@cramforce](https://github.com/cramforce)! - Bug fixes across network, sqlite3, xan, rg, terminal rendering, and CI
311
-
312
- ## 2.14.3
313
-
314
- ### Patch Changes
315
-
316
- - [#199](https://github.com/vercel-labs/just-bash/pull/199) [`3d11f05`](https://github.com/vercel-labs/just-bash/commit/3d11f05959faa205267a5173b25665c6732fee8b) Thanks [@cramforce](https://github.com/cramforce)! - Internal: convert repository to a pnpm workspace under `packages/just-bash` and adopt Changesets for versioning. No public API changes; `import` paths and the `bin` entries are unchanged.
1
+ # just-bash
2
+
3
+ ## 3.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`ff8837a`](https://github.com/JerryAZR/just-bash/commit/ff8837ab0ed617c14ec70a2d7d383384e9c0ff5b) Thanks [@JerryAZR](https://github.com/JerryAZR)! - **VFS template fork model** (`createVfsTemplate`): fork a prepared filesystem into cheap copy-on-write instances for parallel agents, then merge their change sets and apply the result back to the host. **Merge is a replay**: entries from all sources (fork instances or plain diffs — the latter cross process boundaries) are ordered by untamperable `changedAt` stamps (ties by input order) and applied to a fresh fork with the stock filesystem operations over the template's real lower, so metacopy, resurrection, and deletion semantics are definitionally identical to the forks' own. Conflicting (racy) entries are refused exactly as a real filesystem would refuse them — deterministic, never throwing, contained to the conflicted path; no invented conflict-resolution rules. `merge()` returns the merged fork — diff it and discard it, or keep working on it. `diff({ space: "vfs" | "host" })` selects virtual vs host-absolute paths; `template.apply()` validates containment and writes through. `applyDiffToRealFs` remains the standalone host-apply primitive. See `docs/design/vfs-template-fork-model.md` and `docs/recipes/parallel-fan-out.md`.
8
+
9
+ **Bridge: generic oversized-result assembly**: results of ANY size now cross the worker bridge transparently (host publishes a prefix + retains the buffer; the worker assembles with range reads) — one mechanism for file reads, HTTP responses, tool results, exec output, and readdir, replacing the per-channel 8MB ceiling.
10
+
11
+ **Structural hardening** (architecture-level flaw classes closed):
12
+
13
+ - **Builtin manifest**: the three disconnected builtin truths (dispatch chain, display set, unimplemented list) are now one leaf manifest; the dispatch table is typed against it, so a listed-but-undispatchable builtin is a compile error, unrepresentable in code.
14
+ - **Two-word bridge protocol**: request and result channels are separate SAB words, so a result wait can only be woken by a real result publish — the torn-read flake class is unrepresentable (the re-wait tolerance loop is gone; impossible states fail loudly as protocol violations).
15
+ - **Typed fs error codes**: `FsError` carries errnos structurally on `.code`; all ~140 fs throw sites converted, and the five ad-hoc prose-parsing errno heuristics (bridge, python worker, rm/cp/mv/mkdir/ln) are deleted. Unclassifiable errors coerce to honest EIO instead of a fabricated specific errno. A new banned-pattern lint rule makes the legacy `"ECODE: ..."` plain-Error channel unrepresentable in non-test source. `FsError`, `fsErrorCode`, `isFsErrorCode`, `toFsError` are exported; `IFileSystem` documents the error contract.
16
+ - **`mergeDiffs` is O(n log n)**: sort+sweep replaces all-pairs prefix scans (8×5000-entry merge in ~47ms).
17
+
18
+ ## 3.6.1
19
+
20
+ ### Patch Changes
21
+
22
+ - [`f49b787`](https://github.com/JerryAZR/just-bash/commit/f49b7878d9f1b613afac0d58f6f67f4c6e180f85) Thanks [@JerryAZR](https://github.com/JerryAZR)! - Fixes since 3.6.0:
23
+
24
+ - **Windows real-dir modes**: real directories no longer report `0o40666` (no execute bits), which made every real-backed directory untraversable for the python worker (`chdir`/`listdir`/`open` EACCES below the overlay root). Modes are normalized to `0o755` on win32.
25
+ - **Abort/timeout preserves stdout**: output accumulated before an abort or execution deadline is no longer silently discarded — the exact partial output a harness needs on timeout.
26
+ - **js-exec worker leak**: the idle-teardown timer was suppressed by defense-in-depth context deactivation, leaking the worker (and its handles) so any process that ran js-exec could never exit naturally.
27
+ - **Torn bridge read on cancel**: a request-level cancel landing mid-op could surface as a garbage `Error code: 0` guest error instead of a clean timeout exit 124 (the intermittent js-exec CI flake class).
28
+ - **8MB file ceiling removed**: files larger than the 8MB bridge buffer are readable and writable in both worker runtimes (python3 and js-exec) via ranged transport.
29
+ - **Errno honesty**: python no longer reports `FileNotFoundError` for existing files when the backend errors (blanket ENOENT replaced by real mapping, numeric bridge error codes preferred over substring matching, `ENOTEMPTY` added end-to-end).
30
+ - **Binary write corruption**: js-exec `writeFile`/`appendFile` no longer writes `Uint8Array` data as comma-joined text; write data accepts exactly string/Buffer/TypedArray/DataView and throws TypeError otherwise.
31
+ - **Constructor guard**: `Bash({ fs, files })` now throws (files were silently ignored with a custom fs).
32
+ - **Concurrency**: `appendFile` and `sync()` no longer lose concurrent writes (copy-up and detach compare-and-swap).
33
+ - **rm -f**: ENOENT suppression anchored to the error-code prefix — a file named `ENOENT-notes` can't smuggle a real failure past `-f`.
34
+ - Plus review hardening: directory mode/mtime restored at apply, non-normalized change-set paths rejected loudly, `RESULT_LENGTH` overflow guard.
35
+
36
+ ## 3.6.0
37
+
38
+ ### Minor Changes
39
+
40
+ - [`942abb1`](https://github.com/JerryAZR/just-bash/commit/942abb1a41b836757d98a7a47c9c85633b0455ad) Thanks [@JerryAZR](https://github.com/JerryAZR)! - `rm -f` now suppresses only ENOENT errors, matching GNU rm: mount-point (EBUSY) and other failures are reported and exit 1 instead of being silently swallowed. Previously `rm -rf` on a mount point or its parent was a silent no-op with exit 0, while the change set correctly showed nothing had been deleted.
41
+
42
+ `AgentSandbox` gains path conversion helpers: `resolveRealPath(realPath)` maps a real host path to `{ mountPoint, overlay, path }` for direct shadow inspection on the overlay, and `toRealPath(vfsPath)` maps a VFS path to its real host path. Both return null for paths outside the mounted overlays.
43
+
44
+ ## 3.4.2
45
+
46
+ ### Patch Changes
47
+
48
+ - [#381](https://github.com/vercel-labs/just-bash/pull/381) [`d40a42d`](https://github.com/vercel-labs/just-bash/commit/d40a42d514b22da4ed023635d747c8b3f029a6c5) Thanks [@cramforce](https://github.com/cramforce)! - Include the security and transform declaration trees referenced by the package entrypoints and worker declarations in published packages.
49
+
50
+ ## 3.4.1
51
+
52
+ ### Patch Changes
53
+
54
+ - [#373](https://github.com/vercel-labs/just-bash/pull/373) [`2c1831c`](https://github.com/vercel-labs/just-bash/commit/2c1831cc832d4b09ee4e1823526afb6ccca77942) Thanks [@cramforce](https://github.com/cramforce)! - Prevent defense-in-depth violation reporting from recursively overflowing the call stack in host runtimes that wrap `Date.now()`, honor configured main-thread violation exclusions, include actionable exclusion guidance for configurable violations, and keep constructor-execution protections non-excludable.
55
+
56
+ ## 3.4.0
57
+
58
+ ### Minor Changes
59
+
60
+ - [#303](https://github.com/vercel-labs/just-bash/pull/303) [`c5a2a4a`](https://github.com/vercel-labs/just-bash/commit/c5a2a4a35c7490276befa716acae3fe880c1fe89) Thanks [@boramuyar](https://github.com/boramuyar)! - Provide the shadowed bundled command to custom command overrides through `CommandContext.origCommand`.
61
+
62
+ ## 3.3.0
63
+
64
+ ### Minor Changes
65
+
66
+ - [#291](https://github.com/vercel-labs/just-bash/pull/291) [`47f604a`](https://github.com/vercel-labs/just-bash/commit/47f604a7f1e12730318e4c88c7872a5a35383056) Thanks [@trieloff](https://github.com/trieloff)! - jq: add external-argument flags (`--arg`, `--argjson`, `--rawfile`, `--slurpfile`, `--args`, `--jsonargs`) and the `$ARGS` object (`$ARGS.named` / `$ARGS.positional`), matching real jq 1.7.1 behavior including exit codes, error messages, and prototype-sensitive key handling.
67
+
68
+ - [#336](https://github.com/vercel-labs/just-bash/pull/336) [`d97425d`](https://github.com/vercel-labs/just-bash/commit/d97425dff8f51cfd773d22bc009561a09235cd1b) Thanks [@trieloff](https://github.com/trieloff)! - Support user file descriptors (fd >= 3). `exec 3< file`, `N< file` / `N> file` / `N>> file` on any command, `read -u N`, `read <&N`, `>&N`, `N<&M`, and `N<&-` now go through a real descriptor table: a descriptor carries one shared read position, `exec` keeps it open until it is closed, and every other construct — including `done N< file` on a loop — gets it only for the duration of that command.
69
+
70
+ - [#331](https://github.com/vercel-labs/just-bash/pull/331) [`6680247`](https://github.com/vercel-labs/just-bash/commit/66802470837cfac3a58a09e00d37b2070387ba7b) Thanks [@trieloff](https://github.com/trieloff)! - Treat a `-` FILE operand in `grep` as standard input, matching GNU. `grep PATTERN -` now reads stdin instead of failing with "No such file or directory", stdin is labelled `(standard input)` in the multi-file prefix and in `-l`/`-L`/`-c` output, repeated `-` operands see the stream drained by the first one, and `-` is exempt from `-r` recursion and `--include`/`--exclude` filtering.
71
+
72
+ - [#325](https://github.com/vercel-labs/just-bash/pull/325) [`edc7f2f`](https://github.com/vercel-labs/just-bash/commit/edc7f2fac5337cebd19911c5756b76ed02e52090) Thanks [@trieloff](https://github.com/trieloff)! - Support process substitution `<(cmd)` and `>(cmd)`.
73
+
74
+ `<(cmd)` runs `cmd` and substitutes a readable `/dev/fd/N` path backed by an
75
+ in-memory file; `>(cmd)` substitutes a writable path whose contents are fed to
76
+ `cmd` once the outer command finishes. Descriptors are numbered from 63
77
+ downwards like bash and released when the command that opened them completes.
78
+ Process substitutions retain their surrounding word context in assignments,
79
+ conditionals, regular expressions, and heredoc delimiters. Previously any use
80
+ raised `Parse error: Expected redirection target`.
81
+
82
+ - [#327](https://github.com/vercel-labs/just-bash/pull/327) [`eaedb5b`](https://github.com/vercel-labs/just-bash/commit/eaedb5bc34cffd2077b88bb1ccc48ea7e0545a48) Thanks [@trieloff](https://github.com/trieloff)! - Add `grep -f FILE` / `--file=FILE` to read patterns from a file (one per line). Patterns from `-f` OR-combine with `-e` patterns and with each other, `-f -` reads patterns from stdin, empty pattern lines match every line, and an empty pattern file selects nothing (exit 1). Newline-separated `PATTERNS` operands are now split into individual patterns, and `-x` groups alternatives correctly (`^(?:a|b)$`).
83
+
84
+ ### Patch Changes
85
+
86
+ - [#358](https://github.com/vercel-labs/just-bash/pull/358) [`bd1df37`](https://github.com/vercel-labs/just-bash/commit/bd1df37f8ff836355f470e95dcaa004b769d1e61) Thanks [@privatenumber](https://github.com/privatenumber)! - Parse and serialize bare file descriptor variable redirections such as `{output}>output.log` and `{input}<<EOF`. Bare redirects create their target with a command-scoped descriptor, while named command forms keep the allocated descriptor available.
87
+
88
+ - [#347](https://github.com/vercel-labs/just-bash/pull/347) [`abb904b`](https://github.com/vercel-labs/just-bash/commit/abb904b1e126d14aa437b05f006df83117f06db3) Thanks [@privatenumber](https://github.com/privatenumber)! - Fix escaped reserved words being parsed as shell syntax. Unquoted escapes now retain their provenance through lexing and word parsing, including when the word is serialized back to Bash.
89
+
90
+ - [#332](https://github.com/vercel-labs/just-bash/pull/332) [`4f9bdec`](https://github.com/vercel-labs/just-bash/commit/4f9bdec02edb9eb72511546b759cb7e20bc2e27e) Thanks [@trieloff](https://github.com/trieloff)! - Fix `grep -L` exit status to match GNU grep. The status reports whether a line
91
+ was selected, not whether a filename was printed, so `grep -L` now exits 0 when
92
+ every file matched (printing nothing) and 1 when no file matched (printing every
93
+ name) — previously these were inverted.
94
+
95
+ - [#339](https://github.com/vercel-labs/just-bash/pull/339) [`31d247f`](https://github.com/vercel-labs/just-bash/commit/31d247fe3a62f081b4462064da195552ab0a421c) Thanks [@mutewinter](https://github.com/mutewinter)! - network: restore private-range-enforced requests from the bundled build
96
+
97
+ Every request made with `denyPrivateRanges` enabled failed with `Network access denied: DNS pinning unavailable for private IP enforcement`, so `curl` could not reach any host at all. The published ESM bundle was affected; source consumers and the CommonJS bundle were not.
98
+
99
+ The pinned connection owner reads `Agent` and `fetch` off a dynamic `import("undici")`. Node's resolution of the package exposes those as named exports, but the ESM build inlines undici's CommonJS module into a chunk whose namespace carries it under `default` alone, so `Agent` was `undefined` and the `TypeError` from constructing it was reported as a runtime incapable of pinning.
100
+
101
+ The namespace is now normalized before the transport is read off it, which also covers a consumer that bundles just-bash further.
102
+
103
+ - [#336](https://github.com/vercel-labs/just-bash/pull/336) [`d97425d`](https://github.com/vercel-labs/just-bash/commit/d97425dff8f51cfd773d22bc009561a09235cd1b) Thanks [@trieloff](https://github.com/trieloff)! - Stop command groups, function bodies and `eval` from rewinding stdin they never replaced, so `{ { read a; }; read b; }` gives `b` the second line instead of replaying the first.
104
+
105
+ - [#348](https://github.com/vercel-labs/just-bash/pull/348) [`1a7940d`](https://github.com/vercel-labs/just-bash/commit/1a7940ddf91dec8f69125474a40cef1adebabee9) Thanks [@privatenumber](https://github.com/privatenumber)! - Reject unsupported command-leading reserved words in every parser context instead of discarding them or executing them as simple commands. Unknown command AST nodes now fail explicitly instead of returning a successful result.
106
+
107
+ - [#345](https://github.com/vercel-labs/just-bash/pull/345) [`2208a34`](https://github.com/vercel-labs/just-bash/commit/2208a34e27d33a2fce712fbd024875ec60747553) Thanks [@privatenumber](https://github.com/privatenumber)! - Restore command groups and subshells after the process-substitution and stdin-ownership changes were combined without forwarding ownership through inner command dispatch.
108
+
109
+ - [#336](https://github.com/vercel-labs/just-bash/pull/336) [`d97425d`](https://github.com/vercel-labs/just-bash/commit/d97425dff8f51cfd773d22bc009561a09235cd1b) Thanks [@trieloff](https://github.com/trieloff)! - Apply output redirections attached to `while` and `until` loops. `while true; do echo x; break; done >/dev/null` no longer leaks its output to the caller, and `> file`, `>>`, `2>`, `2>&1`, `&>` and `>|` now behave on loops the way they already did on `for` and `case`. `until` loops also gained the input-redirection handling `while` loops already had, so `until ! read l; do ...; done < file` reads from the file. A loop now only restores stdin it owns, so reading inside a loop no longer rewinds an enclosing group's read position: `printf 'a\nb\n' | { while read x; do break; done; read y; }` sees `y=b`.
110
+
111
+ - [#328](https://github.com/vercel-labs/just-bash/pull/328) [`65dafd5`](https://github.com/vercel-labs/just-bash/commit/65dafd55afbfa7e62642ce485787f7d65fad4961) Thanks [@trieloff](https://github.com/trieloff)! - Stop pipelines from draining the enclosing shell's stdin, so `while read …; do … | …; done < file` runs once per line again.
112
+
113
+ - [#349](https://github.com/vercel-labs/just-bash/pull/349) [`be55fec`](https://github.com/vercel-labs/just-bash/commit/be55fec4e23b3f5a42cf8eaeb6939b379f741ae1) Thanks [@privatenumber](https://github.com/privatenumber)! - Process redirections through policy-driven transactions that preserve Bash ordering, descriptor lifetimes, persistent `exec` routes, compound-command stdin, control-flow output routing, and shared read-write descriptor positions without duplicate expansion or opening.
114
+
115
+ - [#368](https://github.com/vercel-labs/just-bash/pull/368) [`3ee215c`](https://github.com/vercel-labs/just-bash/commit/3ee215c2ad56c96ce0d88e2813050df9f15afa38) Thanks [@cramforce](https://github.com/cramforce)! - FS sym-link hardening
116
+
117
+ - [#338](https://github.com/vercel-labs/just-bash/pull/338) [`19a02c2`](https://github.com/vercel-labs/just-bash/commit/19a02c297d110fde8a8a3376d6956c2c549d128e) Thanks [@mutewinter](https://github.com/mutewinter)! - sqlite3: report failed statements on stderr and exit non-zero without `-bail`
118
+
119
+ A statement that failed was written to **stdout** as `Error: ...` and the command still exited `0` unless `-bail` was passed. Real `sqlite3` writes the error to stderr and exits `1` in either mode; `-bail` only decides whether the remaining statements still run.
120
+
121
+ Two consequences for callers: `sqlite3 db "SELECT ..." > out.csv` silently wrote the error text into the data file, and `sqlite3 db "..." && next-step` ran `next-step` after the query had failed, so a shell script could not detect a bad query without opting into `-bail` and losing the ability to see later statements.
122
+
123
+ Errors now accumulate on stderr in statement order and the exit status is `1` whenever any statement failed. Successful runs are unchanged, `-bail` still stops at the first failure, and the partial stdout produced before a failure is still emitted. Writeback of a partially-successful script is also unchanged.
124
+
125
+ - [#360](https://github.com/vercel-labs/just-bash/pull/360) [`1fbde34`](https://github.com/vercel-labs/just-bash/commit/1fbde341d74ff7f933d9cead9a390a6ab65b5df3) Thanks [@privatenumber](https://github.com/privatenumber)! - Preserve whether a here-document ended at its delimiter or at end-of-input. Unterminated final body lines now receive Bash's trailing newline, backslash-newline continuations are removed during expansion, and serialization rejects unterminated documents rather than manufacturing a closing delimiter.
126
+
127
+ ## 3.2.0
128
+
129
+ ### Minor Changes
130
+
131
+ - [#304](https://github.com/vercel-labs/just-bash/pull/304) [`3d39a71`](https://github.com/vercel-labs/just-bash/commit/3d39a714b3751cedc173dffae27933dfe7b8b3b5) Thanks [@subsetpark](https://github.com/subsetpark)! - Add curl `-G`/`--get` query-string data handling and preserve command-line order when repeated `-d`, `--data-raw`, `--data-binary`, and `--data-urlencode` options are mixed, including `@file` forms. Data requests now also set curl's standard `application/x-www-form-urlencoded` content type unless the caller supplies one.
132
+
133
+ - [#307](https://github.com/vercel-labs/just-bash/pull/307) [`7c4caed`](https://github.com/vercel-labs/just-bash/commit/7c4caedf02599628f19b243f960d480760f5e476) Thanks [@cramforce](https://github.com/cramforce)! - Harden untrusted execution with shared aggregate budgets, liberal normal and
134
+ opt-in hardened limit profiles, request-bound network validation, bounded
135
+ archive and worker processing, transactional filesystem and shell state, and
136
+ expanded adversarial regression checks.
137
+
138
+ Established command declarations and host-extension defaults remain source
139
+ compatible. Dispatched callbacks receive a `ResolvedCommandContext` with
140
+ required limits; applications can use `createCommandContext({ fs })` for direct
141
+ invocation, opt into restricted custom-command execution with `trusted: false`,
142
+ and select tighter resource policy with the `hardened` profile. All
143
+ host-registration paths keep their established trusted default. The supported
144
+ Node.js floor is now declared as `>=20.18.1`.
145
+
146
+ ### Patch Changes
147
+
148
+ - [#315](https://github.com/vercel-labs/just-bash/pull/315) [`6df692f`](https://github.com/vercel-labs/just-bash/commit/6df692f236ca108c888552a67557998156ac845b) Thanks [@matchai](https://github.com/matchai)! - Treat `--` as the end of options in `grep`.
149
+
150
+ ## 3.1.0
151
+
152
+ ### Minor Changes
153
+
154
+ - [#284](https://github.com/vercel-labs/just-bash/pull/284) [`af2e0f4`](https://github.com/vercel-labs/just-bash/commit/af2e0f4cdeb5417ea59e25140038c239dd8fd92d) Thanks [@arimxyer](https://github.com/arimxyer)! - sandbox: forward capability flags from `SandboxOptions` into the underlying `Bash`
155
+
156
+ `Sandbox.create(opts)` previously constructed its internal `Bash` with only a subset
157
+ of `BashOptions`, silently dropping the optional capability flags (`python`,
158
+ `javascript`, `commands`, `customCommands`, `fetch`). A host that drives just-bash
159
+ through the `Sandbox` API (rather than `new Bash(...)`) therefore could not enable
160
+ python3, js-exec, a restricted command set, custom commands, or a custom fetch — even
161
+ though the runtimes ship in the package.
162
+
163
+ `SandboxOptions` now exposes those fields and `Sandbox.create` forwards them into the
164
+ `Bash` it builds. Behavior is unchanged when a caller omits them (each falls back to
165
+ its existing `BashOptions` default — Python/js-exec stay off, the full command set
166
+ stays available). Fixes the root cause behind vercel/eve#431.
167
+
168
+ ### Patch Changes
169
+
170
+ - [#268](https://github.com/vercel-labs/just-bash/pull/268) [`7a5a0b9`](https://github.com/vercel-labs/just-bash/commit/7a5a0b9ae3bf0524722653cbf4b45e6bc176cf22) Thanks [@trieloff](https://github.com/trieloff)! - jq: allow nested double-quoted strings inside `"\(...)"` string interpolation
171
+
172
+ jq string interpolation of the form `"\(...)"` that contained a nested double-quoted string — for example `"\(sub("T.*";""))"` or `"\(ltrimstr("ab"))"` — previously failed with a parse error. The tokenizer terminated the outer string at the first `"` it saw inside the interpolation expression, so the rest of the expression became orphaned tokens.
173
+
174
+ The lexer now tracks `\(...)` depth while consuming a string literal and treats nested `"..."` pairs as opaque content while inside an interpolation, restoring them verbatim into the captured interpolation source. `parseStringInterpolation` similarly skips over nested strings when balancing parentheses, so the interpolation expression is captured as a whole and handed to the expression parser intact.
175
+
176
+ ## 3.0.3
177
+
178
+ ### Patch Changes
179
+
180
+ - [#277](https://github.com/vercel-labs/just-bash/pull/277) [`aec5643`](https://github.com/vercel-labs/just-bash/commit/aec56431d7d9b6fcb141bbfe25d26f4931f54f80) Thanks [@mutewinter](https://github.com/mutewinter)! - interpreter: avoid lazy import in variable assignment path that trips defense-in-depth (fixes [#273](https://github.com/vercel-labs/just-bash/issues/273))
181
+
182
+ Any non-`export` variable assignment (bare `SECRET=s`, prefixed `SECRET=s cmd`,
183
+ or before a custom command) failed with a defense-in-depth security violation
184
+ (`dynamic import of Node.js builtin 'node:module' is blocked during script
185
+ execution`), while plain commands and `export`-ed assignments passed.
186
+
187
+ `processScalarAssignment()` resolved `isArray` via `await import("./expansion.js")`
188
+ in two spots. In the bundled `dist`, that dynamic `import()` marks `expansion.js`
189
+ as a lazily-linked chunk whose `createRequire` banner imports `node:module`; the
190
+ defense layer's ESM `resolve` hook blocks that builtin import when the sandbox is
191
+ active and untrusted, so it blocked just-bash's own chunk load. The file already
192
+ statically imports from `./expansion.js`, so `isArray` is now pulled from that
193
+ static import and the two lazy imports are removed — no lazy `node:module`-bearing
194
+ chunk is linked at runtime. No public API change.
195
+
196
+ - [#276](https://github.com/vercel-labs/just-bash/pull/276) [`1ec5eec`](https://github.com/vercel-labs/just-bash/commit/1ec5eec0aefd099d23ac9f056df1e6612c81d49b) Thanks [@mutewinter](https://github.com/mutewinter)! - interpreter: preserve leading whitespace in multi-line quoted strings (fixes [#259](https://github.com/vercel-labs/just-bash/issues/259))
197
+
198
+ `exec()` runs each script through `normalizeScript()`, which `trimStart()`s
199
+ leading indentation from lines so indented template-literal scripts parse. It
200
+ was applied line-by-line and stripped the leading whitespace inside multi-line
201
+ single- and double-quoted strings too. The visible symptom was `python3 -c
202
+ '...'` (and `node -e`, `awk`, etc.) with an indented body failing with
203
+ `IndentationError`, while the same code via heredoc or pipe worked.
204
+
205
+ `normalizeScript()` is now quote-aware (mirroring the earlier heredoc-aware
206
+ fix): it only strips indentation from lines that begin outside any quote, and
207
+ preserves lines that begin inside an unterminated single- or double-quoted
208
+ string verbatim. This also un-skips four sed spec tests whose indented stdin
209
+ was previously being corrupted.
210
+
211
+ - [#286](https://github.com/vercel-labs/just-bash/pull/286) [`cb2b583`](https://github.com/vercel-labs/just-bash/commit/cb2b583b3f46e6bb4e6982c4bfe19903ec811a87) Thanks [@privatenumber](https://github.com/privatenumber)! - interpreter: deliver redirected output to each fd's final target (fixes `cmd > file 2>&1` leaking stderr to stdout)
212
+
213
+ `applyRedirections()` processed a command's redirection list sequentially over
214
+ the result's stdout/stderr strings, moving content at each step. The
215
+ duplication operators (`2>&1`, `1>&2`) merged into the live stream regardless
216
+ of where the source fd pointed, so the canonical `cmd > file 2>&1` wrote
217
+ stdout to the file but leaked stderr onto the caller's stdout — including
218
+ "command not found" errors and custom-command stderr. Any wrapper protocol
219
+ that parses the enclosing script's stdout (e.g. a runner emitting a JSON
220
+ payload after `eval "$CMD" > "$OUT" 2>&1`) saw the leaked stderr corrupt its
221
+ stream. Ordering variants were wrong in other ways: `cmd 2>&1 > file` put
222
+ stderr in the file instead of on stdout, and `cmd > a > b` wrote content to
223
+ `a` instead of `b`.
224
+
225
+ The pass now mirrors how bash sets up fds before running the command: each
226
+ output redirection only opens/truncates its target and re-points the fd's
227
+ sink (file, /dev/null, or a snapshot of the caller-visible stream), and
228
+ duplication operators copy the source fd's current sink. Stream content is
229
+ delivered once, after the whole list is processed, to each fd's final sink.
230
+ This makes `cmd > file 2>&1` send stderr to the file, `cmd 2>&1 > file` keep
231
+ stderr on the caller's stdout, `cmd > all 2>&1 2> err` let the later `2> err`
232
+ reclaim stderr, and `cmd > a > b` truncate `a` while writing content to `b`.
233
+ The `/dev/null`-as-regular-VFS-file behavior for stdout redirects is
234
+ preserved.
235
+
236
+ ## 3.0.2
237
+
238
+ ### Patch Changes
239
+
240
+ - [#272](https://github.com/vercel-labs/just-bash/pull/272) [`150a915`](https://github.com/vercel-labs/just-bash/commit/150a915a1d45a2cc7f2b6aec3268f27116c34916) Thanks [@trieloff](https://github.com/trieloff)! - interpreter: fix UTF-8 mojibake when a script interleaves text-output and byte-output statements
241
+
242
+ A single `exec()` can interleave text-shaped statements (sed, awk, echo — `ö`
243
+ as `U+00F6`) with byte-shaped ones (grep | head, cat — `ö` as bytes
244
+ `0xC3 0xB6`). `executeScript` / `executeStatement` concatenated each result's
245
+ raw stdout, so the lone high byte from the text half made the combined stream
246
+ invalid UTF-8, the output-boundary decoder bailed, and the byte half came back
247
+ as Latin-1 mojibake (`Köpenicker` for `Köpenicker`). The same path backs
248
+ command substitution, so `echo "你好: $(cat /file)"` was affected too.
249
+
250
+ The fix decodes each statement/pipeline result to text via its explicit
251
+ `stdoutKind` (`decodedTextFromResult`) before concatenating — no guessing from
252
+ string contents, so text whose code units merely look like UTF-8 (`ö`) is
253
+ preserved. `tac` (stdin path) and `curl` (response body) now declare
254
+ `stdoutKind: "bytes"` on the results that forward raw bytes, so the decode is
255
+ driven per output rather than by inspecting characters.
256
+
257
+ - [#256](https://github.com/vercel-labs/just-bash/pull/256) [`75d8dfd`](https://github.com/vercel-labs/just-bash/commit/75d8dfd3a322786250e3b0f81b1500c87610acb7) Thanks [@Hazzng](https://github.com/Hazzng)! - js-exec: fix Buffer shim correctness — ascii encode now uses & 0xff (not & 0x7f), consolidate latin1/ascii into shared \_rawEncode, fix Buffer.from(ArrayBuffer, offset, length), throw on invalid byteLength input, clamp negative toString start, throw RangeError for out-of-range write offset
258
+
259
+ - [#239](https://github.com/vercel-labs/just-bash/pull/239) [`1369b77`](https://github.com/vercel-labs/just-bash/commit/1369b772fe887694c09ce834d1b0b21aa6420b59) Thanks [@trieloff](https://github.com/trieloff)! - curl: interpret `@file` for `-d`/`--data`, `--data-binary`, and `--data-urlencode`
260
+
261
+ Real curl reads file contents when these flags are passed `@filename`:
262
+
263
+ - `-d @file` / `--data @file` — read file contents, strip CR/LF.
264
+ - `--data-binary @file` — read file contents verbatim (newlines preserved).
265
+ - `--data-urlencode @file` — read file, URL-encode the contents.
266
+ - `--data-urlencode name@file` — prefix the URL-encoded contents with `name=`.
267
+
268
+ just-bash's curl previously passed `@filename` through verbatim as the HTTP body. Posting JSON or any non-trivial payload via `curl --data-binary @payload.json https://…` sent the literal string `@payload.json` instead of the file. The new behavior matches upstream curl; `--data-raw` keeps the documented "no `@` interpretation" semantics.
269
+
270
+ - [#262](https://github.com/vercel-labs/just-bash/pull/262) [`4ece258`](https://github.com/vercel-labs/just-bash/commit/4ece2580d8cb707e6c6b7fa22897ea3fdd21739a) Thanks [@chernetsov](https://github.com/chernetsov)! - parser: don't treat quotes inside a heredoc body as shell quotes when finding the end of a command substitution
271
+
272
+ A command substitution whose body contained a heredoc with an unbalanced quote in its body — most commonly an apostrophe in literal prose, e.g. `June's` — failed to parse with `bash: syntax error: ... unexpected EOF while looking for matching ')'`:
273
+
274
+ ```bash
275
+ OUT=$(cat <<'SCRIPT'
276
+ June's moon
277
+ SCRIPT
278
+ )
279
+ ```
280
+
281
+ Both the lexer's `$(...)` word scanner and the substitution boundary scanner walked into the heredoc body and applied shell quote tracking to it. The `'` in `June's` opened a single-quoted string that never closed, so the closing `)` was swallowed and the scan ran to EOF. In bash a heredoc body is literal text and must be skipped wholesale when locating the substitution boundary.
282
+
283
+ Both scanners are now heredoc-aware: when scanning a `$(...)` they recognize `<<` / `<<-` operators (but not the `<<<` here-string), capture the possibly-quoted delimiter, and skip the heredoc body lines literally — without quote or paren tracking — up to the terminator. Multiple heredocs on one line and tab-stripping (`<<-`) are handled. This fixes the common pattern of capturing the output of a connector/CLI invocation that is fed a heredoc script containing apostrophes, backticks, or parentheses.
284
+
285
+ The heredoc scan also tracks arithmetic `((...))` nesting so a `<<` left-shift inside `$((...))` (or a nested arithmetic expansion) is not mistaken for a heredoc opener — previously a multi-line arithmetic expansion containing a shift, e.g. `$((\n1 << 2\n))`, had its closing `))` swallowed by spurious body-skipping.
286
+
287
+ - [#248](https://github.com/vercel-labs/just-bash/pull/248) [`d64009a`](https://github.com/vercel-labs/just-bash/commit/d64009aef6bc1556e7c84b22ed455863275ea953) Thanks [@Hazzng](https://github.com/Hazzng)! - perf(grep): up to 14.5× speedup via preFilter extensions and matcher reuse.
288
+
289
+ Anchored alternation patterns like `^def \|^async def` now extract literal needles (stripping outer `^`/`$`), enabling the `String.indexOf` fast-path. Files with no matching needle are rejected before `split("\n")`, skipping RE2 entirely. `acquireMatcher()` extended to `match()`, `replace()`, `search()`, and `matchAll()` to reduce GC pressure across awk/sed hot-paths.
290
+
291
+ - [#261](https://github.com/vercel-labs/just-bash/pull/261) [`c9904de`](https://github.com/vercel-labs/just-bash/commit/c9904dea24ad2aa847749ee6289239c2a2c651fc) Thanks [@chernetsov](https://github.com/chernetsov)! - set: support a bundled `-o`/`+o` long option inside a short-flag cluster (e.g. `set -euo pipefail`)
292
+
293
+ The `set` builtin previously rejected `set -euo pipefail` with `bash: set: -o: invalid option`, because it parsed each character after the `-` as an independent short flag and has no `o` short flag. `-o` was only honored as its own token (`set -eu -o pipefail`).
294
+
295
+ This is the canonical "bash strict mode" idiom and is extremely common in generated scripts, so the whole script would abort on its first line.
296
+
297
+ `set` now matches bash: an `o` inside a cluster consumes the _next word_ as its long-option name, and the remaining characters keep being parsed as short flags. So `set -euo pipefail` is equivalent to `set -e -u -o pipefail`, `set -oe pipefail` enables both `pipefail` and `errexit`, trailing words become positional parameters, and `+`-clusters (`set +euo pipefail`) disable the options. An invalid bundled name (`set -euo bogus`) still reports `invalid option name`, and an `o` with no following argument falls back to the standalone `-o`/`+o` listing.
298
+
299
+ ## 3.0.1
300
+
301
+ ### Patch Changes
302
+
303
+ - [#238](https://github.com/vercel-labs/just-bash/pull/238) [`01a4721`](https://github.com/vercel-labs/just-bash/commit/01a4721324350adea4b035b311f0b60ccdbb65ff) Thanks [@cramforce](https://github.com/cramforce)! - Fix `Dynamic require of "tty" is not supported` crash when invoking commands that transitively load `debug` / `supports-color` (notably `file`) under ESM Node consumers and via the `just-bash` CLI binary.
304
+
305
+ The esbuild dynamic-require shim emitted into the ESM Node bundles had no `require` to delegate to at chunk-init under ESM, so any runtime `require("tty")` / `require("os")` from `file-type` → `debug` chain threw. Build banners now provide `createRequire(import.meta.url)` for `build:lib`, `build:cli`, and `build:shell`. CJS and browser bundles are unchanged.
306
+
307
+ Fixes [#211](https://github.com/vercel-labs/just-bash/issues/211).
308
+
309
+ ## 3.0.0
310
+
311
+ ### Major Changes
312
+
313
+ - [#233](https://github.com/vercel-labs/just-bash/pull/233) [`7cca738`](https://github.com/vercel-labs/just-bash/commit/7cca73831987e3331160f426b7a66d7217b8cf79) Thanks [@cramforce](https://github.com/cramforce)! - Breaking change for stdin byte/utf8-handling. Will break some custom commands that handle stdin
314
+
315
+ ### Minor Changes
316
+
317
+ - [#209](https://github.com/vercel-labs/just-bash/pull/209) [`b3bd85e`](https://github.com/vercel-labs/just-bash/commit/b3bd85ed816445e6d148290163a1900f49ebea82) Thanks [@cramforce](https://github.com/cramforce)! - Introducing plumbing for integrating executor and adding a peer package for the implememtation
318
+
319
+ - [#233](https://github.com/vercel-labs/just-bash/pull/233) [`7cca738`](https://github.com/vercel-labs/just-bash/commit/7cca73831987e3331160f426b7a66d7217b8cf79) Thanks [@cramforce](https://github.com/cramforce)! - TS-enforced correct handling of utf8 on stdin. Impacts many commands
320
+
321
+ ## 2.14.5
322
+
323
+ ### Patch Changes
324
+
325
+ - [#214](https://github.com/vercel-labs/just-bash/pull/214) [`da58f4f`](https://github.com/vercel-labs/just-bash/commit/da58f4f523c5e9c1c444106a0f2a7777a59fb618) Thanks [@subsetpark](https://github.com/subsetpark)! - jq: accept control characters inside JSON strings
326
+
327
+ - [#221](https://github.com/vercel-labs/just-bash/pull/221) [`a835686`](https://github.com/vercel-labs/just-bash/commit/a835686c97f5cac2e5b94bd551d996079a33dfc2) Thanks [@cramforce](https://github.com/cramforce)! - upgrade deps
328
+
329
+ - [#218](https://github.com/vercel-labs/just-bash/pull/218) [`13d78b2`](https://github.com/vercel-labs/just-bash/commit/13d78b2876d7ac7b6bc3a6eacfa3937bbb79665f) Thanks [@Hazzng](https://github.com/Hazzng)! - grep: 5-123x faster pattern matching via RE2 matcher reuse and literal pre-filter
330
+
331
+ ## 2.14.4
332
+
333
+ ### Patch Changes
334
+
335
+ - [#206](https://github.com/vercel-labs/just-bash/pull/206) [`6ccc35f`](https://github.com/vercel-labs/just-bash/commit/6ccc35f5a9b5c6f395b145ed2ec7ee71c4862057) Thanks [@subsetpark](https://github.com/subsetpark)! - Fix awk lexer to honor POSIX statement continuation across newlines after `,`,
336
+ `{`, `&&`, `||`, `?`, `:`, `do`, `else`, `if`, and `while`. Previously, a
337
+ multi-line idiom like `printf "%s=%d\n", \n $1, $2` (comma at end-of-line
338
+ followed by indented args on the next line) failed with `Unexpected token:
339
+ NEWLINE` because the lexer emitted a NEWLINE token unconditionally. The
340
+ lexer now suppresses the NEWLINE when it immediately follows one of the
341
+ continuation-allowing tokens, matching POSIX awk.
342
+
343
+ - [#212](https://github.com/vercel-labs/just-bash/pull/212) [`733c847`](https://github.com/vercel-labs/just-bash/commit/733c84796e3abbd05a25cf67805bf4b030d0b02d) Thanks [@cramforce](https://github.com/cramforce)! - Bug fixes across network, sqlite3, xan, rg, terminal rendering, and CI
344
+
345
+ ## 2.14.3
346
+
347
+ ### Patch Changes
348
+
349
+ - [#199](https://github.com/vercel-labs/just-bash/pull/199) [`3d11f05`](https://github.com/vercel-labs/just-bash/commit/3d11f05959faa205267a5173b25665c6732fee8b) Thanks [@cramforce](https://github.com/cramforce)! - Internal: convert repository to a pnpm workspace under `packages/just-bash` and adopt Changesets for versioning. No public API changes; `import` paths and the `bin` entries are unchanged.