buninu-linux 0.8.55 → 0.9.56

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 (52) hide show
  1. package/NOTICE.md +46 -46
  2. package/README.md +7 -6
  3. package/initramfs/bin/tar +34 -46
  4. package/initramfs/buninu/apps/bunmsh/CHANGELOG.md +103 -0
  5. package/initramfs/buninu/apps/bunmsh/PORTING.md +133 -15
  6. package/initramfs/buninu/apps/bunmsh/help/awk.md +38 -0
  7. package/initramfs/buninu/apps/bunmsh/help/break.md +21 -0
  8. package/initramfs/buninu/apps/bunmsh/help/chmod.md +8 -2
  9. package/initramfs/buninu/apps/bunmsh/help/cmp.md +29 -0
  10. package/initramfs/buninu/apps/bunmsh/help/continue.md +22 -0
  11. package/initramfs/buninu/apps/bunmsh/help/cp.md +4 -0
  12. package/initramfs/buninu/apps/bunmsh/help/diff.md +30 -0
  13. package/initramfs/buninu/apps/bunmsh/help/egrep.md +26 -0
  14. package/initramfs/buninu/apps/bunmsh/help/export.md +2 -2
  15. package/initramfs/buninu/apps/bunmsh/help/expr.md +30 -0
  16. package/initramfs/buninu/apps/bunmsh/help/fgrep.md +25 -0
  17. package/initramfs/buninu/apps/bunmsh/help/grep.md +4 -0
  18. package/initramfs/buninu/apps/bunmsh/help/ls.md +4 -2
  19. package/initramfs/buninu/apps/bunmsh/help/mkdir.md +1 -1
  20. package/initramfs/buninu/apps/bunmsh/help/print.md +3 -0
  21. package/initramfs/buninu/apps/bunmsh/help/return.md +23 -0
  22. package/initramfs/buninu/apps/bunmsh/help/sed.md +8 -3
  23. package/initramfs/buninu/apps/bunmsh/help/set.md +12 -3
  24. package/initramfs/buninu/apps/bunmsh/help/tr.md +4 -0
  25. package/initramfs/buninu/apps/bunmsh/help/trap.md +22 -0
  26. package/initramfs/buninu/apps/bunmsh/help/uniq.md +27 -0
  27. package/initramfs/buninu/apps/bunmsh/package.json +1 -1
  28. package/initramfs/buninu/apps/bunmsh/src/awk.js +203 -0
  29. package/initramfs/buninu/apps/bunmsh/src/diff.js +222 -0
  30. package/initramfs/buninu/apps/bunmsh/src/fancy-ls.js +15 -4
  31. package/initramfs/buninu/apps/bunmsh/src/main.js +21 -5
  32. package/initramfs/buninu/apps/bunmsh/src/sed.js +159 -0
  33. package/initramfs/buninu/apps/bunmsh/src/shell.js +1283 -540
  34. package/initramfs/buninu/apps/bunmsh/test/awk-reference.test.js +35 -0
  35. package/initramfs/buninu/apps/bunmsh/test/awk.test.js +62 -0
  36. package/initramfs/buninu/apps/bunmsh/test/posix-bootstrap.test.js +595 -0
  37. package/initramfs/buninu/apps/bunmsh/test/utility-reference-cases.mjs +98 -0
  38. package/initramfs/buninu/apps/bunmsh/test/utility-reference.test.js +23 -0
  39. package/initramfs/buninu/apps/jsgotty/client-kitty.mjs +61 -0
  40. package/initramfs/buninu/apps/jsgotty/client.mjs +16 -0
  41. package/initramfs/buninu/apps/jsgotty/package-lock.json +2 -2
  42. package/initramfs/buninu/apps/jsgotty/package.json +1 -1
  43. package/initramfs/buninu/apps/jsgotty/tests/client-kitty.test.mjs +43 -0
  44. package/initramfs/etc/resolv.conf +2 -1
  45. package/initramfs/usr/share/doc/buninu-linux/tar.md +12 -1
  46. package/package.json +1 -1
  47. package/scripts/arch.js +5 -5
  48. package/scripts/arch.sh +5 -5
  49. package/scripts/fetch.js +2 -0
  50. package/scripts/npm-packages.md +4 -3
  51. package/test/fetch-npm.test.js +1 -1
  52. package/test/tar-strip.test.js +36 -0
package/NOTICE.md CHANGED
@@ -105,83 +105,83 @@ the built image redistributes them.
105
105
  - License: GPL-2.0-only WITH Linux-syscall-note
106
106
  - See: `LICENSES/GPL-2.0.txt` and `LICENSES/Linux-syscall-note.txt`
107
107
 
108
- Linux 6.18.55 as packaged by Alpine Linux 3.24 from the `linux-lts` aport.
109
- The default build uses package `linux-virt`, version 6.18.55-r0.
110
- `--linux-lts` and `--real` use package `linux-lts`, version 6.18.55-r0.
108
+ Linux 6.18.56 as packaged by Alpine Linux 3.24 from the `linux-lts` aport.
109
+ The default build uses package `linux-virt`, version 6.18.56-r0.
110
+ `--linux-lts` and `--real` use package `linux-lts`, version 6.18.56-r0.
111
111
  Each comes from the x86_64 or aarch64 repository to match `--arch`. All
112
112
  listed modules are the selected package's `.ko.gz` files decompressed without
113
113
  modification.
114
114
 
115
- - Upstream source: https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.18.55.tar.xz
115
+ - Upstream source: https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.18.56.tar.xz
116
116
  - Alpine build recipe, configuration and patches (Corresponding Source),
117
- pinned to the commit shipping 6.18.55-r0 (the same for both architectures):
118
- https://gitlab.alpinelinux.org/alpine/aports/-/blob/52fae6d7d56f3958f32e5bf9121a7536524b9ef4/main/linux-lts/APKBUILD
117
+ pinned to the commit shipping 6.18.56-r0 (the same for both architectures):
118
+ https://gitlab.alpinelinux.org/alpine/aports/-/blob/efc8ddbb20c827d2bd8223c19a2625e754e5cb3c/main/linux-lts/APKBUILD
119
119
  - Packages:
120
- https://dl-cdn.alpinelinux.org/alpine/v3.24/main/x86_64/linux-virt-6.18.55-r0.apk
121
- SHA-256 `a941c15fc5db26b6692fd0140fa0970da76cb12aadf3dc8306c419f21bd39c93`
122
- https://dl-cdn.alpinelinux.org/alpine/v3.24/main/x86_64/linux-lts-6.18.55-r0.apk
123
- SHA-256 `02ba9491d4cc110707de64ed03dd7e2fa5c93fdd851979c244ceb018785a9eea`
124
- https://dl-cdn.alpinelinux.org/alpine/v3.24/main/aarch64/linux-virt-6.18.55-r0.apk
125
- SHA-256 `c7fb892408d7fe163a18671e5c7816752976d1c67fd17794dfba794aa0d6c1ac`
126
- https://dl-cdn.alpinelinux.org/alpine/v3.24/main/aarch64/linux-lts-6.18.55-r0.apk
127
- SHA-256 `31aeae56fa527b2fb4fdd4aefbd693cbec210a8cbfd4ea7597a1773b832e9f83`
120
+ https://dl-cdn.alpinelinux.org/alpine/v3.24/main/x86_64/linux-virt-6.18.56-r0.apk
121
+ SHA-256 `755deb045cfeb8c2bcaa2b2febe01ab2101d747921e64d4cd54d0312321e8d5d`
122
+ https://dl-cdn.alpinelinux.org/alpine/v3.24/main/x86_64/linux-lts-6.18.56-r0.apk
123
+ SHA-256 `b0d8cc4d7e031b5619221e7978920d051bf1dd1e335f6d05d03964b2285fc3b4`
124
+ https://dl-cdn.alpinelinux.org/alpine/v3.24/main/aarch64/linux-virt-6.18.56-r0.apk
125
+ SHA-256 `e3839bfd751ff0a4421484f712b9b29efb514024523736a0ef62521521571b12`
126
+ https://dl-cdn.alpinelinux.org/alpine/v3.24/main/aarch64/linux-lts-6.18.56-r0.apk
127
+ SHA-256 `795bcd49840be7f4ff9566f5f669201bd41202376a455b720a98eb814f0e72f8`
128
128
 
129
129
  SHA-256 of files in the default x86_64 `linux-virt` image:
130
130
 
131
131
  ```text
132
- kernel/x86_64/vmlinuz-virt fcee60bd42bdcc5f165278e092de0bb00d969843be326f7bd9a9602c2f52de9e
133
- failover.ko 75d408861dd0ee89bf94753c9f2fff0f3831a6f76eaab8870d186910e6e2924b
134
- net_failover.ko 4db140c0f8e32a31e95f56f35af62e5279864104f57d30af0684c75e3505bdd5
135
- virtio_net.ko f2867d641f808b7f5d7d4eb972c72398902589a83b48f6f7a174b844717da117
132
+ kernel/x86_64/vmlinuz-virt dc99c86bb8e58cb4eda5f01eac44c4d972105945a46dfe76a9e86e8529915c72
133
+ failover.ko ddf94fe8a89b24e839f21866f828adc3eb91e62fa46dd977c74d7c2b6f92fe21
134
+ net_failover.ko fb710ef0450417dea2f6dede919d14f5a4a94b1be73f338cfe2ed05e32f0cc30
135
+ virtio_net.ko 2fb98ab7d06cfb7a1e1a07dcc5098da44316360097d75e288a30ad4855c449f7
136
136
  ```
137
137
 
138
138
  SHA-256 of files in an x86_64 `--linux-lts` image:
139
139
 
140
140
  ```text
141
- kernel/x86_64/vmlinuz-lts 6c85e6375814c51257a3d1b21c3c4c02803231d42e42c1a3d50236bf543cbeba
142
- failover.ko b563c6734384c5c41ed1b227a221a3e7b511bca743e583dd33d6f85405a8df07
143
- net_failover.ko 4ee36e32ed5db502125b57d237b5db31509c7b9c9a49ca9221b704fcfcd80b1c
144
- virtio_net.ko 4aa2b98c0fed35be473ff22f4d3f89cb184ca13e6605dd9e8a68b5854eba7b6a
145
- virtio_ring.ko ed1c704eddca74e4f68164efc62b65f8e8a8276b7ebb2eeb0185326dbd093603
146
- virtio.ko 986cab65ecfce9c6291cc54598301ede8e8e2eca521a82dfbaf6dcf76ec6f8c6
147
- virtio_pci_legacy_dev.ko dedd092324e5d23ac218dfa2aad3fa8bc2f0b49e54c1763423627c75a8c4e907
148
- virtio_pci_modern_dev.ko 855221097ff07f0981d4e9fbb4200a0628a154826f37299d1434811f21902388
149
- virtio_pci.ko aee0a18cce24968d1e06c026a056e570b3039884b900385f019410a751ea8a44
141
+ kernel/x86_64/vmlinuz-lts e893ce0f7aecbdf2dcf012659ec5a0b35740780ae5c3af5ad188029f5cd4aa8f
142
+ failover.ko 59e4e4808dca2d18d849c2da850e4ea659485007b09a690c7e57fb0e623cd1df
143
+ net_failover.ko 20dd06a6f6f1528079a438630d741f125d11cc9bae58d618e0e6381f8bff6f5c
144
+ virtio_net.ko 39bcd12bfc3149351fa226dabdbb1f82137c53f3b1ccbacbf30661bf8ff99ad4
145
+ virtio_ring.ko e8fdebd89345ef39a54d3b23e6f2a57c6c4b201708b35113705b56d0fa373596
146
+ virtio.ko d4ab148e31f5d4d5a1dd3c3f30bb52ba9a13e670929c9f7f1668396edf8049b7
147
+ virtio_pci_legacy_dev.ko 15c35c8875b68dcaed3ac58d463d1b3f2c3e52dcf9a3840366d3fa6da7cd4dd7
148
+ virtio_pci_modern_dev.ko 59bd6e34e6cf3c0ce54bab1eca1d7ac0325112280a6718613460002d2cde70d0
149
+ virtio_pci.ko cc3ad8eaffa321bd58dbd663afba074dee81a5ad6f283d50cd5b1b340672430e
150
150
  ```
151
151
 
152
152
  `--real` additionally includes the following modules from that same
153
153
  x86_64 `linux-lts` package for physical xHCI controllers and USB HID keyboards:
154
154
 
155
155
  ```text
156
- usb-common.ko 38a461cdee1e8dd82985fedbd050d3a496825c5b59c66dc3305c5508c93fb0e4
157
- usbcore.ko 18949ea4cab0f98846f4fea192c9ebe9892c5504f6750529a4db8c1a718fdd3b
158
- xhci-hcd.ko aed7f3e8d2f1e2d722fb625fcd68adce5212a30ce1a25a934832177594670543
159
- xhci-pci.ko 8959b6c1790ac1b656308278313f78cf4fde8b811456a42579b467a8196515b8
160
- xhci-pci-renesas.ko 3aa013b9ca71ee5bd16b30efb1f68aa2c29ac84cf15dd92caf413f7577fc36cf
161
- hid.ko e3fecc9b96b44d1c572337a937927291c3219d43a00a357049a1285ab57f5bbe
162
- hid-generic.ko a3d76a35904f26d8bb8d5bff115de12a1cb966c3e428e529767dde28c24e4421
163
- usbhid.ko 6b50c4a6037fa740b3f576d5bf362bdad7aa86ebc8da5e1777e69c03ed70f703
156
+ usb-common.ko 37feaa14670d4bbd3dca77d701344d2fb02e2cb139d21c5af8b2c140aab5c6fe
157
+ usbcore.ko 75efddfd7d1bf996ad99f0d9be790be767ca72ebdb53a00194b449c3588faa16
158
+ xhci-hcd.ko bd5772b2ba908dff16c74ae10211a1e5cfd72910d861dbdf30b8f71c5995066a
159
+ xhci-pci.ko 6c688038c9b45297fce752c8f0443cd0f398f31e0b4efffd7f869325ce9884fa
160
+ xhci-pci-renesas.ko aa08808c9e609fe570a1c5b90d0f0ba33f2ca2e7d84e8ccbb3a2856fe65a7b3f
161
+ hid.ko 161160bf12d18a24c25aef6355e265142fc4fb2122b09923a6e184fabedf6246
162
+ hid-generic.ko 6d5ae3cfd8f8b034cbe444869485ac9012376c4ca604a3cd039f0cae442005f9
163
+ usbhid.ko 6ed1e4891b242f64520621d689a24828dfc24a96236c71b86d9af9361248aa5a
164
164
  ```
165
165
 
166
166
  SHA-256 of files in the default aarch64 `linux-virt` image:
167
167
 
168
168
  ```text
169
- kernel/aarch64/vmlinuz-virt af8ad21e222dbff8c89909e1ef7b8b7607dd58188b2f3067128aac4f646d212d
170
- failover.ko aff1648d08436515b509c3c848049e44540ff0d26afc113a496db961f6871df6
171
- net_failover.ko 4461014c041c8cbdfc881c0d820361014a491547b694d36425d084ab9008a33f
172
- virtio_net.ko 7b6e3c89d666419d336990688711c4d6b0cab91e5934a7bd99e6d8dcc5caa40b
169
+ kernel/aarch64/vmlinuz-virt 039c532c2fa8f49896a679065d79a03b8a444c9d54fa80ac9bc4d0ce1ecd0ca6
170
+ failover.ko ce65a98acce98720753c4a9a7e339f6c70d22eae70b65cc1b4211543a7c6c3a3
171
+ net_failover.ko 39c9222d800ae95d8a82ff797e408187411ac2ff47bec2c9d7ddbfe99537dbe3
172
+ virtio_net.ko 762f8e362ae2e2bbf200ab9bc742524999e8bce12c72671bf8560fd9bb7907d5
173
173
  ```
174
174
 
175
175
  SHA-256 of files in an aarch64 `--linux-lts` image:
176
176
 
177
177
  ```text
178
- kernel/aarch64/vmlinuz-lts 6c6625bc5ba59136101414d09efbeaaed000517e654a75157f42565cec15abad
179
- failover.ko 1f10c1ac74c6d35f745227899372b1b6656a3197436d9c72e0bb39a19779c3a6
180
- net_failover.ko 5815342b859f820adfd90ffdddde689c73f0e6fcc34efbc9ada8beabb2fd37b2
181
- virtio_net.ko 2ef9114dea6b40bd9d2e1460c6be94859b5527af5479928cfd90a66eff843bab
182
- virtio_pci_legacy_dev.ko be6654a06cfb30f2598b184f7a2b2372314c5a5325a984b73a7ef9a3c39e7eb3
183
- virtio_pci_modern_dev.ko d88219ed14678c0aba06a882d6cf43b0ad9462eeae09638b6382ba5601b5a8c4
184
- virtio_pci.ko 6bdafb0472d289e2ca6dfc63bf2cb2e54e1258e9c4774317ca1c7df059dfb31e
178
+ kernel/aarch64/vmlinuz-lts de5ff95fd663a30e53765cb0794707656bb80749d77f16bbf94225d17c512447
179
+ failover.ko 7f3d40067603c9916d22e9d85fea1512bd95c087aaae774e5ea70f8bacb7ae04
180
+ net_failover.ko 085e4fd53a40704408b6bf914ee464d16007296fa3615940fa54688afe84466c
181
+ virtio_net.ko 4ea86521819063df91cfd18191e8bc2bd2551392e8f7a33126df0aba675ee409
182
+ virtio_pci_legacy_dev.ko baf8033c183819a8bccacf36677247740a5cff9eec9b403b94840af258b60b6e
183
+ virtio_pci_modern_dev.ko 2905133de7c9baceff9fc6a27dba9b8469744019545c19cf1456e64f7e50f062
184
+ virtio_pci.ko 3b506947c25866e08a311f124cd143bd0f501179f0b556aed7ca4d6632143d8d
185
185
  ```
186
186
 
187
187
  ### linuxx64.efi.stub and linuxaa64.efi.stub
package/README.md CHANGED
@@ -1112,7 +1112,7 @@ initramfs/ init.js, commands, userspace: the same for every archi
1112
1112
  native/<arch>/ musl and the GCC runtime (committed); bun and modules (fetched)
1113
1113
  ```
1114
1114
 
1115
- The `--real` inputs are Alpine v3.24 `linux-lts-6.18.55-r0`, musl `1.2.6-r2`,
1115
+ The `--real` inputs are Alpine v3.24 `linux-lts-6.18.56-r0`, musl `1.2.6-r2`,
1116
1116
  `systemd-efistub-260.2-r0`, `libstdc++`/`libgcc` `15.2.0-r5`, and Bun 1.4.2
1117
1117
  `linux-x64-musl-baseline`. The aarch64 guest uses the same versions from
1118
1118
  Alpine's aarch64 repository and Bun's `linux-aarch64-musl`. There is no BusyBox
@@ -1127,10 +1127,11 @@ extracts from it. Bumping a version changes both the file name and the hash, so
1127
1127
  it always refetches.
1128
1128
 
1129
1129
  The four application packages are pinned separately in
1130
- `scripts/npm-packages.md`: `buninu-browser@0.2.2`,
1130
+ `scripts/npm-packages.md`: `buninu-browser@0.2.3`,
1131
1131
  `@drxiaozhi/casty@1.3.4`, `@drxiaozhi/jspulse@0.2.1`, and
1132
1132
  `@drxiaozhi/jspinyin@0.1.1`. These were npm's `latest` versions when checked
1133
- on 2026-10-11; fetch never resolves `latest` or a version range at runtime.
1133
+ on 2026-10-11, with buninu-browser updated to npm's `latest` on 2026-10-12;
1134
+ fetch never resolves `latest` or a version range at runtime.
1134
1135
  Each registry tarball was checked against its published SHA-512 integrity
1135
1136
  before its SHA-256 was recorded in the shared pins file.
1136
1137
 
@@ -1274,7 +1275,7 @@ The physical boot chain is firmware → the UKI stub → its embedded
1274
1275
  and, with the currently pinned kernel, embeds this complete command line:
1275
1276
 
1276
1277
  ```text
1277
- console=ttyS0,115200 console=tty0 REAL_MACHINE=1 panic=0 PATH=/bin KERNEL_RELEASE=6.18.55-0-lts rdinit=/bin/bun -- -e import('/init.js')
1278
+ console=ttyS0,115200 console=tty0 REAL_MACHINE=1 panic=0 PATH=/bin KERNEL_RELEASE=6.18.56-0-lts rdinit=/bin/bun -- -e import('/init.js')
1278
1279
  ```
1279
1280
 
1280
1281
  Serial kernel logging is retained, while the final console makes
@@ -1298,7 +1299,7 @@ the same way). Build without `--real`; this selects Alpine `linux-virt`, omits t
1298
1299
  module set, and puts `ttyS0` last so serial stdio owns `/dev/console`:
1299
1300
 
1300
1301
  ```text
1301
- console=tty0 console=ttyS0,115200 panic=0 PATH=/bin KERNEL_RELEASE=6.18.55-0-virt rdinit=/bin/bun -- -e import('/init.js')
1302
+ console=tty0 console=ttyS0,115200 panic=0 PATH=/bin KERNEL_RELEASE=6.18.56-0-virt rdinit=/bin/bun -- -e import('/init.js')
1302
1303
  ```
1303
1304
 
1304
1305
  Build and boot it with:
@@ -1415,7 +1416,7 @@ The default `--real` image embeds this kernel command line (shown for the
1415
1416
  currently pinned LTS release):
1416
1417
 
1417
1418
  ```text
1418
- console=ttyS0,115200 console=tty0 REAL_MACHINE=1 panic=0 PATH=/bin KERNEL_RELEASE=6.18.55-0-lts rdinit=/bin/bun -- -e import('/init.js')
1419
+ console=ttyS0,115200 console=tty0 REAL_MACHINE=1 panic=0 PATH=/bin KERNEL_RELEASE=6.18.56-0-lts rdinit=/bin/bun -- -e import('/init.js')
1419
1420
  ```
1420
1421
 
1421
1422
  The physical display (`tty0`) is the final console and therefore owns PID 1's
package/initramfs/bin/tar CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/bin/bun
2
2
  // tar — a small tar/gzip/zstd CLI over Bun.Archive.
3
3
 
4
+ import { gunzipSync } from "node:zlib";
4
5
  import { lstat, readdir } from "node:fs/promises";
5
6
  import { linkSync, mkdirSync, rmSync, symlinkSync } from "node:fs";
6
7
  import { basename, dirname, join, resolve } from "node:path";
@@ -180,11 +181,20 @@ const scanEntries = (bytes) => {
180
181
  let longName = null;
181
182
  let longTarget = null;
182
183
  let extended = {};
184
+ let ended = false;
185
+ entries.concatenated = false;
183
186
  while (offset + BLOCK <= bytes.length) {
184
187
  const block = bytes.subarray(offset, offset + BLOCK);
185
188
  offset += BLOCK;
186
- if (block.every((byte) => byte === 0)) break; // end-of-archive blocks
189
+ if (block.every((byte) => byte === 0)) {
190
+ // APK v2 joins tar streams; another header may follow the end markers.
191
+ ended = true;
192
+ longName = longTarget = null;
193
+ extended = {};
194
+ continue;
195
+ }
187
196
  if (!checksumMatches(block)) return entries.length ? entries : null;
197
+ if (ended) { entries.concatenated = true; ended = false; }
188
198
  const flag = String.fromCharCode(block[156] || 0x30);
189
199
  const size = extended.size !== undefined ? Number(extended.size) : octal(block, 124, 12);
190
200
  const dataBlocks = Math.ceil(size / BLOCK) * BLOCK;
@@ -227,7 +237,7 @@ const scanEntries = (bytes) => {
227
237
  };
228
238
 
229
239
  const tarBytes = (bytes) => {
230
- if (bytes[0] === 0x1f && bytes[1] === 0x8b) return Bun.gunzipSync(bytes);
240
+ if (bytes[0] === 0x1f && bytes[1] === 0x8b) return gunzipSync(bytes);
231
241
  if (bytes[0] === 0x28 && bytes[1] === 0xb5 && bytes[2] === 0x2f && bytes[3] === 0xfd) {
232
242
  return Bun.zstdDecompressSync(bytes);
233
243
  }
@@ -292,59 +302,37 @@ const restoreLinks = (entries) => {
292
302
  }
293
303
  };
294
304
 
295
- // Opt-in path only: keep the existing Bun.Archive extraction unchanged for
296
- // ordinary extraction and --strip-components=0 without excludes. Reuse the
297
- // scanned-entry extractor for excludes: no glob whitelist can accidentally
298
- // reinterpret literal metacharacters in retained archive names.
299
- if (options.operation === "x" && (options.strip > 0 || options.excludes.length)) {
305
+ // Read stdin only once. node:zlib expands every concatenated gzip member
306
+ // (APK signature, control and data), rather than just the first stream.
307
+ if (options.operation === "x" || options.operation === "t") {
300
308
  try {
301
309
  const bytes = tarBytes(await archiveBytes());
302
- const entries = scanEntries(bytes);
303
- if (!entries) throw new Error("invalid tar archive");
310
+ const scanned = scanEntries(bytes);
304
311
  const wanted = options.operands.length ? patterns().map((pattern) => new Bun.Glob(pattern)) : null;
312
+ const useScannedExtraction = options.strip > 0 || options.excludes.length || scanned?.concatenated;
313
+ if (useScannedExtraction && !scanned) throw new Error("invalid tar archive");
314
+ // Bun.Archive stops at the first tar end marker. Use the existing scanned
315
+ // extractor when later streams contain more entries; ordinary tar files
316
+ // retain the Bun.Archive extraction path.
317
+ const archive = useScannedExtraction ? null : new Bun.Archive(bytes);
318
+ const entries = scanned ?? [...(await archive.files(options.operands.length ? patterns() : undefined))]
319
+ .map(([name, file]) => ({ name, kind: "file", target: "", size: file.size, mode: 0o644, mtime: file.lastModified }));
305
320
  const members = entries.filter((entry) => !excluded(entry.name)
306
321
  && !(entry.kind === "hardlink" && excluded(entry.target))
307
322
  && (!wanted || wanted.some((glob) => glob.match(entry.name))));
308
- extractStripped(bytes, members, options.directory, options.strip, {
309
- verbose: options.verbose, filtered: options.operands.length > 0 || options.excludes.length > 0,
310
- });
311
- } catch (error) {
312
- fail(error?.message || String(error));
313
- }
314
- process.exit(0);
315
- }
316
-
317
- if (options.operation === "x" || options.operation === "t") {
318
- let archive;
319
- try {
320
- archive = new Bun.Archive(await archiveBytes());
321
- } catch (error) {
322
- fail(error?.message || String(error));
323
- }
324
-
325
- // The header scan is what makes listing and links complete; if the bytes
326
- // do not parse as tar, fall back to what Bun.Archive reports.
327
- const scanned = scanEntries(tarBytes(await archiveBytes()));
328
- const wanted = options.operands.length ? patterns().map((pattern) => new Bun.Glob(pattern)) : null;
329
- const members = scanned
330
- ? scanned.filter((entry) => !wanted || wanted.some((glob) => glob.match(entry.name)))
331
- : [...(await archive.files(options.operands.length ? patterns() : undefined))]
332
- .map(([name, file]) => ({ name, kind: "file", target: "", size: file.size, mode: 0o644, mtime: file.lastModified }));
333
-
334
- if (options.operation === "t") {
335
- for (const entry of members.filter((entry) => !excluded(entry.name))) {
336
- console.log(options.verbose ? verboseListing(entry) : entry.name);
337
- }
338
- } else {
339
- try {
340
- if (options.verbose) {
341
- for (const entry of members) console.log(entry.name);
342
- }
323
+ if (options.operation === "t") {
324
+ for (const entry of members) console.log(options.verbose ? verboseListing(entry) : entry.name);
325
+ } else if (useScannedExtraction) {
326
+ extractStripped(bytes, members, options.directory, options.strip, {
327
+ verbose: options.verbose, filtered: options.operands.length > 0 || options.excludes.length > 0,
328
+ });
329
+ } else {
330
+ if (options.verbose) for (const entry of members) console.log(entry.name);
343
331
  await archive.extract(options.directory, options.operands.length ? { glob: patterns() } : undefined);
344
332
  restoreLinks(members);
345
- } catch (error) {
346
- fail(error?.message || String(error));
347
333
  }
334
+ } catch (error) {
335
+ fail(error?.message || String(error));
348
336
  }
349
337
  process.exit(0);
350
338
  }
@@ -2,6 +2,109 @@
2
2
 
3
3
  All notable user-visible changes to bunmsh are documented here.
4
4
 
5
+ ## [0.4.0] - 2026-10-13
6
+
7
+ ### Added and fixed
8
+
9
+ - Respect builtin cat output redirects in shell subprocesses, including AWK pipes.
10
+
11
+ - Stream external stdout/stderr to the correct pipeline endpoint for `2>&1`,
12
+ `2>&1 >file` and `1>&2`, retaining downstream early-close handling.
13
+
14
+ - Support `cp -p` for regular files, preserving ownership, mode and timestamps.
15
+
16
+ - Evaluate `!` inside if/elif conditions with normal pipeline precedence,
17
+ including conditions joined with `&&` or `||`.
18
+
19
+ - AWK supports parenthesized print lists, continued arguments and buffered
20
+ output command pipes through bunmsh. Correct function parameter scope and
21
+ preserve replacement backslashes; GCC option generators match mawk output.
22
+
23
+ - Process mkdir operands in order so parent/child paths do not race.
24
+
25
+ - Preserve here-document bodies when connecting commands to compound operands.
26
+
27
+ - Distinguish backquoted brace groups from parameter expansions during tokenization.
28
+
29
+ - Handle traditional set - as an option delimiter, preserving bare-call arguments.
30
+
31
+ - Add byte-preserving adjacent-line uniq with -c/-d/-u and input/output files.
32
+ - Ignore empty nonexistent filenames with rm -f, including libtool cleanup.
33
+
34
+ - Recognize case/esac next to subshell parentheses, including nested groups.
35
+
36
+ - Keep awk quoted operator strings as data, including install path concatenation.
37
+
38
+ - Remove the backquote escape layer before parsing command substitutions.
39
+
40
+ - Preserve short circuiting across comments before compounds and parse simple
41
+ pipeline stages before a trailing compound command.
42
+
43
+ - Keep persistent read descriptors open and consume one line without read-ahead.
44
+ - Expand positional parameter lengths such as libtool's ${#1}.
45
+
46
+ - Support explicit-class chmod rwxX modes such as a-w and u+rw.
47
+
48
+ - Recognize comments after else and loop-closing done as compound syntax.
49
+
50
+ - Apply enclosing descriptor redirects to compound-producer pipeline output.
51
+
52
+ - Add bytewise cmp, legacy egrep/fgrep names, and tr squeeze/delete combinations.
53
+ - Adapt mv/rm -- for Bun Shell while protecting option-looking filenames.
54
+
55
+ - Preserve multiline parameter expansion operands inside compound bodies.
56
+ - Accept combined print flags such as Autoconf's -rn.
57
+ - Preserve compound commands and function declarations after recipe continuations.
58
+
59
+ - Match quoted literals and bracket patterns in parameter prefix/suffix removal.
60
+ - Capture subshell state at execution time and scope its internal transport to
61
+ that command, preserving changes from earlier commands in the same list.
62
+ - Treat interior ^ and $ as literals in basic regular expressions, including
63
+ GNU make build.sh object-extension substitutions.
64
+
65
+ - Add a pure JavaScript awk fallback interpreter with fields, arrays, rules,
66
+ functions, loops, string/regex operations and file I/O. Input command pipes
67
+ and system() remain unsupported; full POSIX/GNU compatibility is not claimed.
68
+ - Preserve multiline quoted operands after compound pipeline connectors, quoted
69
+ backslash-newlines, heredoc AND/OR continuations, and case terminators after groups.
70
+ - Preserve ASCII control characters used as Autoconf awk separators during expansion.
71
+ - Keep nested redirected compound operands when reconstructing pipelines.
72
+ - Support sed r FILE, including end-of-cycle output and silently missing files.
73
+
74
+ - Add offline system diff/sed reference fixtures so isolated tests can compare
75
+ output and exit status without depending on host executables in the guest.
76
+
77
+ - Add file diff using the jsmdcui Myers line alignment, with separate insertion,
78
+ deletion and replacement hunks, binary notices and missing-final-newline markers.
79
+ - Expand parameters and substitutions inside arithmetic, including Autoconf `$(( $* ))`.
80
+
81
+ - In `set -o posix` mode, send only exported variables and command-prefix
82
+ assignments to external programs, while preserving complete internal state
83
+ for pipeline/subshell Bun children. Default mode still passes all variables.
84
+ - Match newlines with case wildcards, including Autoconf POSIX-mode detection.
85
+ - Keep heredoc contents out of subshell rewriting, support pipelines feeding
86
+ compound cases, accept operand-free rm -f, grep -e/-c, and sed -f.
87
+
88
+ - Track command source lines, preserve quotes and argument boundaries in selected
89
+ parameter operands, and parse nested compound conditions and subshell cases.
90
+ - Add expr and extend fallback sed with addresses, branches and hold-space edits.
91
+ - Make `set -o posix` an observable option: only this mode removes fallback ls
92
+ icons and implicit directory suffixes. Normal ls and lsfancy retain icons.
93
+ - Support ls inode/dereference options and sorting multiple file operands.
94
+ - Transport large internal subprocess state through a private temporary file;
95
+ retain the full function AST and clean up after foreground execution.
96
+
97
+ - Accept inline and next-line function braces, brace groups with redirects and
98
+ pipelines, multiline pipelines, and nested case clauses with here-documents.
99
+ - Implement return and counted break/continue with function/source/loop boundaries.
100
+ - Add persistent numeric fd bindings for exec, ordered duplication, scoped
101
+ restoration, and descriptor inheritance for external and subshell commands.
102
+ - Add conditional errexit, nounset/noglob, xtrace, option queries, EXIT handlers
103
+ and deferred signal traps. See PORTING.md for the remaining POSIX boundaries.
104
+ - Preserve the minimal background-command contract: original Bun.Subprocess
105
+ objects, append-only stable Bun.sha.procs indices, immediate return and unref;
106
+ no implicit waiting, killing or widening of accepted background syntax.
107
+
5
108
  ## [0.3.11] - 2026-10-12
6
109
 
7
110
  ### Fixed
@@ -38,8 +38,28 @@ pseudo-terminal tests.
38
38
  Background pipelines, builtins, functions, and all redirections are rejected
39
39
  before files are opened. General asynchronous command lists, job control,
40
40
  and coprocesses are not implemented.
41
- - Brace command groups, `select`, arithmetic commands, and `[[ ... ]]` are
42
- not implemented.
41
+ Compatibility invariant: keep the original `Bun.Subprocess` objects in an
42
+ append-only `Bun.sha.procs` array with stable indices, immediate return and
43
+ `unref()`. POSIX foreground work must not add implicit waiting, killing,
44
+ removal of completed entries, or a job-wrapper replacement.
45
+ - Brace command groups run in the current shell, including scoped redirects
46
+ and group pipelines. `select`, arithmetic commands, and `[[ ... ]]` remain
47
+ unimplemented. Function opening braces may be on the same or next line;
48
+ inline bodies and nested case clauses are supported.
49
+ - `return` stops at the function/source boundary; `break N` and `continue N`
50
+ unwind enclosing loops. Functions and sourced files establish their own
51
+ loop boundary, following mksh STOP_BRKCONT.
52
+ - `set -e` uses a dynamically inherited error-ignore context for conditions,
53
+ non-final AND/OR commands and negation, following mksh XERROK. `set -u`,
54
+ `set -f`, `set -x`, option queries and corresponding CLI flags are supported.
55
+ `-v` currently prints initial CLI input only; it is not an incremental reader.
56
+ `set -o posix` is listed and stored as an option. It makes fallback `ls`
57
+ omit icons and automatic directory suffixes; `lsfancy` remains decorative.
58
+ External environments in this mode contain only inherited/exported names
59
+ and command-prefix assignments. Full variables and export attributes travel
60
+ with internal pipeline/subshell state, separately from the native environment.
61
+ Default mode continues passing all shell variables to external programs.
62
+ It does not imply full POSIX conformance.
43
63
  - Functions and subshells cover practical cases but do not yet reproduce every
44
64
  mksh scoping, local-variable, trap, and diagnostic edge case.
45
65
  - Pipelines isolate builtin/function state through subprocess copies. Changes
@@ -75,9 +95,17 @@ pseudo-terminal tests.
75
95
  pathname expansion, or tilde expansion, and a trailing newline is appended.
76
96
  It follows the same dash/`/bin/sh` comparison harness as everything else in
77
97
  this codebase, except `<<<` itself, since dash does not implement it.
78
- - Arbitrary descriptor allocation/manipulation, descriptor variables,
79
- heredocs targeting a descriptor other than stdin, and every ordering edge
80
- case remain incomplete.
98
+ - Numeric file descriptors support file open, append, read/write (`<>`),
99
+ duplication and shell-level closure, with left-to-right redirect ordering.
100
+ `exec` without a command persists bindings. Compound/function redirections
101
+ restore only the descriptors they changed; native open handles retained by
102
+ another binding stay alive. External/pipeline children inherit extra fds
103
+ through Bun.spawn stdio. No native compiler or host shell is required.
104
+ - Descriptor variables and heredocs targeting non-stdin fds are not implemented.
105
+ Closing a descriptor denies subsequent shell duplication/use, but Bun.spawn
106
+ maps a closed child stdio slot to `ignore` (/dev/null), not native EBADF.
107
+ Aliases of captured stdout/stderr passed as extra fds to an arbitrary external
108
+ program do not yet reproduce every pipe/capture ordering case.
81
109
  - External processes use `Bun.spawn`; regular and fallback builtins may execute
82
110
  in-process or in a self-spawned bunmsh pipeline child depending on streaming
83
111
  and state-isolation requirements.
@@ -96,13 +124,16 @@ pseudo-terminal tests.
96
124
  - Ctrl-D on an empty readline input sends EOF and exits the interactive shell.
97
125
  This is deliberately distinct from Ctrl-C, following the same high-level
98
126
  editor/main-loop separation used by mksh.
99
- - The current implementation handles SIGINT through readline while editing and
100
- through a process signal listener while a foreground operation owns the
101
- terminal. It does not yet have mksh's general pending-signal table and safe
102
- trap checkpoints.
103
- - There is no `trap` builtin or support for user handlers for signals, `EXIT`,
104
- or `ERR`. Signal handlers therefore cannot yet execute shell source, be
105
- listed, ignored, reset, or inherited with POSIX/mksh semantics.
127
+ - `trap` supports listing, reset (`-`), shell-local ignore (empty action),
128
+ EXIT/0 and catchable signal names/numbers. Signal callbacks enqueue handlers;
129
+ shell source runs at command boundaries, following mksh's pending-trap model.
130
+ Handlers preserve `$?`; EXIT runs once and can explicitly override status.
131
+ Shell finalization releases its fd resources and listeners, never background
132
+ subprocesses or Bun.sha.procs entries.
133
+ - Complete native signal semantics are not claimed: ignored handlers do not
134
+ establish inherited SIG_IGN in external children, handlers waiting at an idle
135
+ interactive prompt run at the next command boundary, and there is no ERR trap,
136
+ process-group forwarding, `wait` integration or general builtin cancellation.
106
137
  - Status 130 is defined for an interrupted `serve`, and its SIGTERM path uses
107
138
  143. Signal-derived statuses are not yet normalised consistently for every
108
139
  external command, builtin, pipeline stage, and command substitution.
@@ -182,11 +213,11 @@ pseudo-terminal tests.
182
213
 
183
214
  ## Remaining major work
184
215
 
185
- 1. Background jobs, process groups, complete signal-status handling, traps,
216
+ 1. General background jobs, process groups, complete signal/trap inheritance,
186
217
  general builtin cancellation, and `jobs`/`fg`/`bg`/`wait`.
187
- 2. Shell options such as `errexit`, `nounset`, `pipefail`, `xtrace`, and POSIX
218
+ 2. Full shell-option edge cases, `pipefail`, incremental verbose input and POSIX
188
219
  mode, plus startup/login/restricted-shell files and modes.
189
- 3. Brace groups, `[[ ... ]]`, arithmetic commands,
220
+ 3. `[[ ... ]]`, arithmetic commands,
190
221
  extended globs, process substitution, and fuller mksh expansion semantics.
191
222
  4. Arrays, associative arrays, namerefs, `typeset`/scope semantics, and more
192
223
  complete special builtins.
@@ -194,3 +225,90 @@ pseudo-terminal tests.
194
225
  `fc`, and automatic history policy.
195
226
  6. Broader POSIX conformance testing, mksh `check.t` coverage, exact diagnostics,
196
227
  and exit-status compatibility for edge cases.
228
+
229
+ ## Bootstrap compatibility verification (2026-10-13)
230
+
231
+ Implementation reference: sibling `mksh/syn.c` (`function_body`/brace grammar),
232
+ `exec.c` (TBRACE, XERROK, E_LOOP), `funcs.c` (c_exitreturn, c_brkcont, c_trap),
233
+ and `histrap.c` (runtrap/cleartraps). The JavaScript execution and descriptor
234
+ model is adapted to Bun; no C code or native signal/job-control layer is copied.
235
+
236
+ `test/posix-bootstrap.test.js` covers finite control-flow, descriptor, trap,
237
+ option and background-registry cases without requiring a reference shell.
238
+ Tests were run with musl Bun 1.4.2 in `bunproot -r rfs1`. The guest's `/bin/sh`
239
+ is itself bunmsh, so reference.test.js comparisons there would not constitute
240
+ an independent POSIX oracle.
241
+
242
+ The next configure compatibility batch adds physical source-line tracking for
243
+ ordinary commands and nested function/case bodies, quoted parameter operands
244
+ (including `${1+"$@"}`), compound conditions containing nested groups/if, and
245
+ multiline subshells containing case clauses. LINENO handling is not yet complete
246
+ for every condition, eval, subshell, or user-assignment edge case.
247
+
248
+ The sed fallback now has addresses/ranges, labels/branches, pattern/hold-space
249
+ operations, and text commands; expr provides arithmetic/comparison/BRE matching.
250
+ File diff uses the jsmdcui Myers alignment and normal-format change hunks;
251
+ directory comparison and unified/context output are not implemented.
252
+ Subprocess state still includes the complete function AST. Large internal state
253
+ uses a private temporary file cleaned by the spawning foreground process. This
254
+ avoids the observed bunproot environment-string limit without changing the
255
+ Bun.sha.procs registry or background process lifecycle.
256
+
257
+ GNU make 4.4.1 configure validation is ongoing; no complete run is claimed.
258
+ Its LINENO/re-exec blockers and large unexported test-source environment values
259
+ have dedicated regressions. Autoconf's multiline case wildcard now detects the
260
+ listed posix option and enables it. Further utility/parser blockers may remain.
261
+
262
+ Independent utility references can be recorded outside the bootstrap guest with
263
+ `node test/utility-reference-cases.mjs OUTPUT.json`, using `/usr/bin/diff` and
264
+ `/usr/bin/sed`. Make only that JSON data accessible inside the guest, then run
265
+ `BUNMSH_UTILITY_REFERENCE=/guest/OUTPUT.json bun test test/utility-reference.test.js`.
266
+ The test compares status, stdout and stderr from explicit bunmsh builtins; it
267
+ does not invoke or mount host reference executables. Without the environment
268
+ variable, the reference fixture suite is skipped explicitly.
269
+
270
+ The current 13 file-diff and 15 sed cases passed under musl Bun/bunproot against
271
+ GNU diffutils 3.10 and GNU sed 4.9. They cover middle edits, repeated lines,
272
+ newline boundaries, UTF-8, sed script files, addresses, branches, hold space and file reads.
273
+ These are selected compatibility cases, not a claim of complete GNU behavior.
274
+
275
+ The awk fallback is a JavaScript parser/interpreter in src/awk.js, with no
276
+ native awk or FFI dependency. It supports BEGIN/END, pattern/action records,
277
+ fields, associative arrays, functions/control flow, regex/string operations,
278
+ getline and file redirection. Output command pipes run through bunmsh, with
279
+ input buffered until close or program end; streaming and interactive pipe
280
+ communication are not supported. Input command pipes and system() fail
281
+ explicitly. JavaScript regex, string and numeric behavior imposes remaining
282
+ locale/formatting limits; this is not full POSIX or GNU awk compatibility.
283
+ The optional test/awk-reference.test.js suite compares a separately supplied
284
+ BUNMSH_AWK_REFERENCE executable; it is never used by the builtin itself.
285
+
286
+ ### Additional Autoconf regressions
287
+
288
+ Compound normalization removes only lexer-recognized line continuations; it
289
+ preserves backslash-newlines inside single quotes and heredoc bodies. Case `;;`
290
+ terminators remain adjacent after brace groups. AND/OR operators continue across
291
+ heredoc bodies, and pipelines retain redirected compound operands. Expansion
292
+ markers use reserved Unicode noncharacters instead of ASCII control bytes, so
293
+ Autoconf's BEL separator reaches awk intact. Sed `r FILE` appends raw file data
294
+ at the end of the cycle (including after `d`); missing files contribute nothing.
295
+
296
+ GNU make build.sh additionally exercises bracket/quoted parameter trimming and
297
+ subshell snapshots taken at execution time. Internal state transport is scoped
298
+ to its command even outside POSIX mode; default user variable export behavior
299
+ and the background process registry are unchanged. Basic regex anchors are
300
+ context-sensitive so literal make variable references can be substituted.
301
+
302
+ Binutils bootstrap coverage additionally includes multiline `${...}` operands
303
+ inside compound bodies, legacy egrep/fgrep fallback names, bytewise cmp (normal
304
+ and quiet modes), tr squeezing with optional translation/deletion, and an
305
+ adapter for Bun Shell mv's missing `--` support. The adapter protects filenames
306
+ beginning with `-` by prefixing `./` after removing the option delimiter. The
307
+ cmp and tr subset has offline GNU command reference fixtures;
308
+ unsupported extensions remain errors, not successful no-ops.
309
+
310
+ The uniq fallback preserves byte comparisons and adjacent groups, supports
311
+ -c/-d/-u, -- and input/output operands. Other GNU extensions are explicit
312
+ errors. Twelve GNU reference fixtures cover ordering, flags, blank lines,
313
+ missing final newlines and NUL bytes. rm -f discards empty nonexistent path
314
+ operands before Bun Shell can incorrectly treat them as the current directory.
@@ -0,0 +1,38 @@
1
+ ## awk
2
+
3
+ Scan records and evaluate AWK programs using a JavaScript interpreter.
4
+
5
+ ### Usage
6
+
7
+ ```sh
8
+ awk [-F SEPARATOR] [-v NAME=VALUE] [-f SCRIPT_FILE] [PROGRAM] [FILE ...]
9
+ ```
10
+
11
+ ### Options and forms
12
+
13
+ - `-F`: Set the field separator; `-v`: assign a variable before BEGIN.
14
+ - `-f`: Read program text from a file; `-e`: append program text.
15
+ - BEGIN/END, pattern/action rules, fields, variables, associative arrays,
16
+ functions, conditionals, loops, next/nextfile, exit and delete.
17
+ - print/printf, arithmetic, comparisons, regular expressions, concatenation,
18
+ split, substr, index, length, match, sub/gsub and common numeric functions.
19
+ - getline from input or files; file output with `>` and `>>`; close.
20
+ - Parenthesized print/printf lists and continued arguments after commas.
21
+ - Output pipes run through bunmsh, buffering input until close or program end.
22
+ They do not provide streaming or interactive communication. close returns
23
+ the command status; closing and reopening starts a fresh command.
24
+ - This is a subset, not full POSIX/GNU compatibility. Input command pipes and
25
+ system() are unsupported and report errors. Text processing uses JavaScript strings
26
+ and regular expressions; locale and floating-point edge cases may differ.
27
+
28
+ ### Example
29
+
30
+ ```sh
31
+ printf 'apple 2\npear 3\n' | awk '{total += $2} END {print total}'
32
+ ```
33
+
34
+ Output:
35
+
36
+ ```text
37
+ 5
38
+ ```