buninu-linux 0.9.56 → 0.11.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 (50) hide show
  1. package/LICENSES/MIT-ZilchOS-bootstrap-from-tcc.txt +21 -0
  2. package/NOTICE.md +48 -2
  3. package/README.md +81 -12
  4. package/initramfs/bin/buninu-land +26 -0
  5. package/initramfs/bin/chroot +68 -47
  6. package/initramfs/buninu/CHANGELOG.md +22 -0
  7. package/initramfs/buninu/apps/jsgotty/package-lock.json +2 -2
  8. package/initramfs/buninu/apps/jsgotty/package.json +1 -1
  9. package/initramfs/buninu/apps/jsgotty/static/js/gotty.js +1 -0
  10. package/initramfs/buninu/package.json +1 -1
  11. package/initramfs/lib/bunterm/geometry.js +15 -0
  12. package/initramfs/lib/bunterm/pointer-report.js +10 -0
  13. package/initramfs/lib/bunterm/terminal.js +5 -4
  14. package/initramfs/lib/chroot-options.js +69 -0
  15. package/initramfs/usr/lib/bootstrap/1.prepare-rootfs.js +106 -0
  16. package/initramfs/usr/lib/bootstrap/10.build-m4.js +40 -0
  17. package/initramfs/usr/lib/bootstrap/11.build-flex.js +50 -0
  18. package/initramfs/usr/lib/bootstrap/12.build-gcc.js +261 -0
  19. package/initramfs/usr/lib/bootstrap/2.enter-rootfs.js +49 -0
  20. package/initramfs/usr/lib/bootstrap/3.gen-musl-dev.js +141 -0
  21. package/initramfs/usr/lib/bootstrap/4.build-tcc.js +61 -0
  22. package/initramfs/usr/lib/bootstrap/5.build-make.js +58 -0
  23. package/initramfs/usr/lib/bootstrap/6.build-binutils.js +77 -0
  24. package/initramfs/usr/lib/bootstrap/7.build-gmp.js +68 -0
  25. package/initramfs/usr/lib/bootstrap/8.build-mpfr.js +59 -0
  26. package/initramfs/usr/lib/bootstrap/9.build-mpc.js +55 -0
  27. package/initramfs/usr/lib/bootstrap/LICENSE +21 -0
  28. package/initramfs/usr/lib/bootstrap/LICENSES/MIT-ZilchOS-bootstrap-from-tcc.txt +21 -0
  29. package/initramfs/usr/lib/bootstrap/NOTICE.md +65 -0
  30. package/initramfs/usr/lib/bootstrap/README.md +204 -0
  31. package/initramfs/usr/lib/bootstrap/downloads.md +49 -0
  32. package/initramfs/usr/lib/bootstrap/lib/build.js +155 -0
  33. package/initramfs/usr/lib/bootstrap/lib/common.js +134 -0
  34. package/initramfs/usr/lib/bootstrap/lib/compile-object.c +14 -0
  35. package/initramfs/usr/lib/bootstrap/lib/musl-headers.js +59 -0
  36. package/initramfs/usr/lib/bootstrap/lib/seed.js +148 -0
  37. package/initramfs/usr/lib/bootstrap/lib/startup-check.c +14 -0
  38. package/initramfs/usr/lib/bootstrap/lib/tcc-build.js +53 -0
  39. package/initramfs/usr/lib/bootstrap/sources/musl-1.2.6.tar.gz +0 -0
  40. package/initramfs/usr/lib/bootstrap/sources/tinycc-05f0faf-upstream.tar.gz +0 -0
  41. package/initramfs/usr/lib/bootstrap/sources/tinycc-local-bootstrap-files.tar.gz +0 -0
  42. package/initramfs/usr/share/doc/buninu-linux/bunterm.md +4 -1
  43. package/initramfs/usr/share/doc/buninu-linux/chroot.md +37 -3
  44. package/package.json +1 -1
  45. package/scripts/npm-packages.md +8 -3
  46. package/test/bootstrap.test.js +65 -0
  47. package/test/bunterm-pixelmouse.test.js +27 -0
  48. package/test/chroot-bind.test.js +70 -0
  49. package/test/fetch-npm.test.js +2 -2
  50. package/test/stage-npm.test.js +42 -1
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Alexander Sosedkin.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE.md CHANGED
@@ -18,6 +18,40 @@ Alpine's CDN serves only the current pkgrel of each branch, so the package
18
18
  URLs below stop working once a build is superseded. The pinned aports commits
19
19
  are permanent and are the Corresponding Source for each exact build.
20
20
 
21
+ ## Bootstrap source archives
22
+
23
+ `initramfs/usr/lib/bootstrap/sources/` additionally carries uncompiled source:
24
+
25
+ - musl 1.2.6, from https://musl.libc.org/releases/musl-1.2.6.tar.gz;
26
+ its full `COPYRIGHT` is preserved inside the archive.
27
+ - TinyCC commit `05f0faf`, with `COPYING` and per-file license notices preserved
28
+ in `tinycc-05f0faf-upstream.tar.gz`.
29
+ - Local TinyCC bootstrap recipes in `tinycc-local-bootstrap-files.tar.gz`.
30
+
31
+ ### Bootstrap route credit and build-time downloads
32
+
33
+ Credit to [ZilchOS/bootstrap-from-tcc](https://github.com/ZilchOS/bootstrap-from-tcc)
34
+ by Alexander Sosedkin (Copyright (c) 2021 Alexander Sosedkin), whose bootstrap
35
+ route and recipes informed Buninu's TinyCC-to-GCC stages. The complete MIT
36
+ notice is preserved in `LICENSES/MIT-ZilchOS-bootstrap-from-tcc.txt` and in
37
+ the bootstrap payload. Reference checkout:
38
+ `d2f9454b34fef570cfb32cf5b17d85a90dba81bf`.
39
+
40
+ Stages 5–12 additionally fetch GNU Make 4.4.1, Binutils 2.39, GMP 4.3.2,
41
+ MPFR 2.4.2, MPC 0.8.1, GNU m4 1.4.18, Flex 2.6.4 and the pinned GCC 4.7
42
+ vendor snapshot. These source archives and compiled results are not bundled
43
+ in the npm package. Their own licenses apply, independently of Buninu's and
44
+ ZilchOS's MIT licenses.
45
+
46
+ See [the bootstrap-specific notices](initramfs/usr/lib/bootstrap/NOTICE.md)
47
+ for component licenses, provenance, runtime-helper exceptions and where
48
+ upstream license texts are retained. The credit and MIT license are copied
49
+ into each prepared rootfs and the final result's license directory.
50
+
51
+ The numbered bootstrap scripts extract these sources into the new rootfs.
52
+ See `initramfs/usr/lib/bootstrap/README.md` for the source-generation steps
53
+ and the ARM64 ordinary-CRT compatibility adjustment.
54
+
21
55
  ## Components tracked in this repository
22
56
 
23
57
  These files are committed under `native/x86_64/lib/` and
@@ -250,8 +284,9 @@ committed source files, but their contents are redistributed in the image.
250
284
 
251
285
  | Package | Version | Package license | Project / package page | Installed license and notices (relative to `/usr/lib/node_modules/`) |
252
286
  |---|---|---|---|---|
253
- | `buninu-browser` | 0.2.2 | MIT for the browser's own code; bundled components retain their own terms | https://github.com/jjtseng93/buninu-browser | `buninu-browser/LICENSE`, `THIRD_PARTY_NOTICES.md`, `LICENSES/` and vendor notices within that package |
254
- | `@drxiaozhi/casty` | 1.3.4 | MIT | https://github.com/jjtseng93/casty | `@drxiaozhi/casty/LICENSE` |
287
+ | `buninu-browser` | 0.2.3 | MIT for the browser's own code; bundled components retain their own terms | https://github.com/jjtseng93/buninu-browser | `buninu-browser/LICENSE`, `THIRD_PARTY_NOTICES.md`, `LICENSES/` and vendor notices within that package |
288
+ | `buninu-land` | 0.1.2 | MIT for its own code; bundled components retain their own terms | https://github.com/jjtseng93/buninu-land | `buninu-land/LICENSE`, `THIRD_PARTY_NOTICES.md`, `LICENSES/`, `SOURCES.md`, protocol XML notices and vendor notices |
289
+ | `@drxiaozhi/casty` | 1.3.6 | MIT | https://github.com/jjtseng93/casty | `@drxiaozhi/casty/LICENSE` |
255
290
  | `@drxiaozhi/jspulse` | 0.2.1 | LGPL-2.1-or-later, with additional component notices | https://github.com/jjtseng93/jspulse | `@drxiaozhi/jspulse/LICENSE`, `NOTICE.md`, `LICENSES/` and source-file notices within that package |
256
291
  | `@drxiaozhi/jspinyin` | 0.1.1 | MIT; hanzipinyin material under the Unlicense | https://www.npmjs.com/package/@drxiaozhi/jspinyin | `@drxiaozhi/jspinyin/LICENSE` and `@drxiaozhi/jspinyin/LICENSE-hanzipinyin.md` |
257
292
 
@@ -283,6 +318,17 @@ LGPL-2.1-or-later. Within `/usr/lib/node_modules/buninu-browser/`, retain:
283
318
  The decoder's `cpu.wasm` remains a separate, replaceable file. Do not remove
284
319
  the source archive or rebuild material merely to reduce the image size.
285
320
 
321
+ ### Buninu Land
322
+
323
+ The compositor package is extracted in full, including its CanvasKit WASM,
324
+ loader, protocol XML, source provenance, patches and license collection.
325
+ Retain `THIRD_PARTY_NOTICES.md`, `SOURCES.md`, `vendor-manifest.json`,
326
+ `LICENSES/`, `vendor/canvaskit/LICENSE`, and the notices embedded in the
327
+ Wayland protocol XML files. These cover Buninu Browser-derived code,
328
+ CanvasKit/Skia and embedded libraries, Wayland protocols, and the Hyprland
329
+ window-management/input reference credit (`LICENSES/hyprland.txt`).
330
+ The distribution-owned launcher uses the separately bundled Casty package.
331
+
286
332
  ### jspulse source and notices
287
333
 
288
334
  jspulse is shipped as JavaScript source, with its LGPL license, modification
package/README.md CHANGED
@@ -47,6 +47,9 @@
47
47
  + Simplified browser works: buninu-browser natively or casty in chroot debian
48
48
  + Playing YouTube with sound (experimental); see [Playing YouTube with sound](#playing-youtube-with-sound-experimental)
49
49
  + See [Buninu Browser](#buninu-browser-early-stage-experimental) for the built-in browser, or [Debian and Chromium with casty](#debian-and-chromium-with-casty) for the optional chroot setup
50
+ * [Bootstrap a C compiler from Bun](initramfs/usr/lib/bootstrap/README.md):
51
+ + numbered scripts generate musl headers/CRT,
52
+ + build TinyCC and download the sources needed to continue through GCC 4.7, starting with `bun /usr/lib/bootstrap/1.prepare-rootfs.js`.
50
53
 
51
54
  ---
52
55
 
@@ -686,6 +689,7 @@ If there is no sound, check step 4's terminal for errors, and make sure
686
689
  | --- | --- | --- |
687
690
  | `buninu-linux-help` | render this buninu-linux README from `/usr/share/doc/buninu-linux/README.md` | `buninu-linux-help` |
688
691
  | `buninu-browser` | early-stage, experimental JavaScript/WASM browser with the bundled casty terminal frontend; not yet a general-purpose browser replacement | `buninu-browser --help` |
692
+ | `buninu-land` | experimental software-rendered Wayland compositor with the bundled casty terminal frontend | `buninu-land --help` |
689
693
  | `jspulse` | PulseAudio-compatible audio server and ALSA mixer controls; use `--alsa` on Buninu Linux | `jspulse --help` |
690
694
  | `jspinyin` | Chinese pinyin input panel, opened with the system jsmdcui in TUI mode; not a system-wide input method | — |
691
695
  | `mount` | `mount(2)` with type detection, `-o` parsing, `LABEL=`/`UUID=`, bind/move/remount; loads required filesystem and disk modules | `mount --help` → `/usr/share/doc/buninu-linux/mount.md` |
@@ -704,7 +708,7 @@ If there is no sound, check step 4's terminal for errors, and make sure
704
708
  | `mmd`, `mcopy`, `mdir` | create directories, copy files and list contents in a FAT image without mounting it; use `-i IMAGE` and `::/path` | — |
705
709
  | `parted` | create and inspect GPT partitions in a disk image; script-mode subset | `parted --help` |
706
710
  | `stripansi` | remove ANSI escape sequences from stdin, `-`, or one or more files and concatenate the results | — |
707
- | `chroot` | `chroot(2)` into another root directory, mounting `/proc`, `/sys`, `/dev`, `/dev/pts`, `/run`, `/tmp` and `/etc/resolv.conf` for you and unmounting them afterwards | `chroot --help` |
711
+ | `chroot` | `chroot(2)` into another root directory, mounting `/proc`, `/sys`, `/dev`, `/dev/pts`, `/run`, `/tmp` and `/etc/resolv.conf` for you; supports `-b HOST[:GUEST]` and `--shared-tmp`, with automatic cleanup on exit | `chroot --help` |
708
712
  | `bunterm` | a graphical terminal on the framebuffer: Skia (CanvasKit) text with CJK, colour emoji, seamless box drawing, kitty graphics images, with the mouse working, wheel scrollback included (`--no-mouse` turns it off); xterm.js's emulator core over Bun's built-in PTY | `bunterm --help` |
709
713
 
710
714
  Besides `bun` (and `sh`/`node` pointing at it), `/bin` includes the commands
@@ -735,6 +739,32 @@ REPL, then run `jspulse --alsa` in another terminal or use `jspulse --alsa &` to
735
739
  buninu-browser about:audio
736
740
  ```
737
741
 
742
+ ### Buninu Land (early-stage, experimental)
743
+
744
+ Run `buninu-land` inside `bunterm` (or another Kitty-graphics terminal) to
745
+ open the Wayland desktop. The compositor and Casty are bundled; startup
746
+ requires no npm download.
747
+
748
+ ```sh
749
+ buninu-land
750
+ ```
751
+
752
+ The socket directory defaults to `$TMPDIR`, or the system temporary directory
753
+ if `TMPDIR` is unset; an explicitly set `XDG_RUNTIME_DIR` takes precedence.
754
+ No environment setup is needed to launch the compositor.
755
+
756
+ In another terminal, set the Wayland client's `XDG_RUNTIME_DIR` to that socket
757
+ directory and `WAYLAND_DISPLAY` to the compositor's socket name (normally `wayland-buninu`;
758
+ additional instances use `wayland-buninu1`, `wayland-buninu2`, and so on),
759
+ then start a Wayland client. Clients inside a chroot can share the socket
760
+ with `chroot --shared-tmp` when the host's `TMPDIR` points to that directory.
761
+
762
+ The `/bin/buninu-land` launcher sets `CASTY_BROWSER` to
763
+ `/usr/lib/node_modules/buninu-land/compositor.js` and runs the bundled Casty.
764
+ `--casty` forwards arguments to Casty; `--headless`, `--help`, `--version`,
765
+ README options and reserved native frontends go through the package entry.
766
+ The package's CanvasKit WASM and license files are retained unchanged.
767
+
738
768
  ### Archive tools and other examples
739
769
 
740
770
  The small `tar` reads the archive's own headers for links and listing, so
@@ -869,9 +899,45 @@ apk add libgcc libstdc++
869
899
  # and /etc/resolv.conf are mounted for you and removed again on exit
870
900
  chroot /mnt
871
901
  chroot /mnt /bin/bun --version
872
- chroot -n /mnt /bin/sh # traditional: mount nothing
902
+ chroot -n /mnt /bin/sh # skip automatic mounts (explicit -b still applies)
873
903
  ```
874
904
 
905
+
906
+ Share host files and directories with repeatable `-b` options, placed before
907
+ the root filesystem path:
908
+
909
+ ```sh
910
+ # Mount a host directory at a different path inside the guest
911
+ chroot -b /home/user/project:/work /mnt /bin/sh
912
+
913
+ # Omit the guest path to expose the same absolute path inside the guest
914
+ chroot -b /home/user/project /mnt /bin/sh
915
+
916
+ # Share multiple paths, including individual files
917
+ chroot -b /home/user/project:/work -b /etc/hosts:/etc/hosts /mnt /bin/sh
918
+
919
+ # Share the host temporary directory, including Wayland sockets
920
+ export TMPDIR=/tmp
921
+ chroot --shared-tmp /mnt /bin/sh
922
+ # Equivalent to:
923
+ chroot -b "$TMPDIR:/tmp" /mnt /bin/sh
924
+ ```
925
+
926
+ `--shared-tmp` expands to `-b "$TMPDIR:/tmp"` and replaces the automatic
927
+ `/tmp` tmpfs. `TMPDIR` must be set and its source path must exist. The option
928
+ does not rewrite environment variables inside the guest; set `TMPDIR=/tmp`
929
+ there if the host uses a different path. For Buninu Land clients, set the
930
+ guest's `XDG_RUNTIME_DIR=/tmp` and `WAYLAND_DISPLAY` to the compositor's socket
931
+ name, and ensure the host's `TMPDIR` is the directory containing that socket.
932
+
933
+ Host paths may be relative; guest paths must be absolute. Missing guest
934
+ mount destinations are created. Directories are bound recursively, and a
935
+ repeated destination uses the last argument. Bind failures abort setup and
936
+ clean up its mounts, even with `-k`. Normally mounts are removed when the
937
+ command exits; `-k` / `--keep-mounts` keeps them after a successful setup.
938
+ Use `-v` to report mounts and unmounts. Full details: `chroot --help` or the
939
+ [chroot manual](initramfs/usr/share/doc/buninu-linux/chroot.md).
940
+
875
941
  ## Environment and dependencies
876
942
 
877
943
  The default JS build uses host Bun. The native build-tool dependencies below
@@ -1098,7 +1164,7 @@ index.js entry point: -f / -b / -r / --arch / --docker / --expo
1098
1164
  Dockerfile Debian-based oven/bun:1.4.2 plus the shell build toolchain
1099
1165
  fetch-alpine.sh [fetch] kernel, EFI stub, musl, network/input/display modules
1100
1166
  fetch-bun.sh [fetch] Bun, libstdc++, libgcc
1101
- fetch-npm.sh [fetch] pinned browser, casty, jspulse and jspinyin tarballs (download only)
1167
+ fetch-npm.sh [fetch] pinned browser, land, casty, jspulse and jspinyin tarballs (download only)
1102
1168
  build-uki.sh [build] UKI; calls scripts/pack-initramfs.sh
1103
1169
  build-image.sh [build] GPT disk image; shared with the hello-world EFI
1104
1170
  run-qemu.sh [run] QEMU q35 (x86_64) or virt (aarch64), KVM/HVF/TCG
@@ -1126,11 +1192,12 @@ tampered with is fetched again and has to pass the same hash before a script
1126
1192
  extracts from it. Bumping a version changes both the file name and the hash, so
1127
1193
  it always refetches.
1128
1194
 
1129
- The four application packages are pinned separately in
1130
- `scripts/npm-packages.md`: `buninu-browser@0.2.3`,
1131
- `@drxiaozhi/casty@1.3.4`, `@drxiaozhi/jspulse@0.2.1`, and
1195
+ The five application packages are pinned separately in
1196
+ `scripts/npm-packages.md`: `buninu-browser@0.2.3`, `buninu-land@0.1.2`,
1197
+ `@drxiaozhi/casty@1.3.6`, `@drxiaozhi/jspulse@0.2.1`, and
1132
1198
  `@drxiaozhi/jspinyin@0.1.1`. These were npm's `latest` versions when checked
1133
- on 2026-10-11, with buninu-browser updated to npm's `latest` on 2026-10-12;
1199
+ on 2026-10-11, with buninu-browser updated on 2026-10-12, and
1200
+ casty 1.3.6 and buninu-land 0.1.2 verified on 2026-10-16;
1134
1201
  fetch never resolves `latest` or a version range at runtime.
1135
1202
  Each registry tarball was checked against its published SHA-512 integrity
1136
1203
  before its SHA-256 was recorded in the shared pins file.
@@ -1156,7 +1223,7 @@ dependency resolution run. JS extraction uses the initramfs JS `tar` and
1156
1223
  requires a host Bun; shell/Docker extraction uses the host `tar`, without Bun.
1157
1224
  The source `initramfs/` and project `package.json` are not modified by packing.
1158
1225
 
1159
- The image gets `/usr/lib/package.json` with the four exact dependencies and
1226
+ The image gets `/usr/lib/package.json` with the five exact dependencies and
1160
1227
  standard `node_modules/.bin` links. This reserves a normal package-manager
1161
1228
  layout for later `cd /usr/lib` and `bun i --backend=copyfile`; no lockfile is
1162
1229
  fabricated. `bun i` alone retains the pinned versions, not newer releases.
@@ -1553,6 +1620,7 @@ for the userspace session.
1553
1620
  * [Playing YouTube with sound (experimental)](#playing-youtube-with-sound-experimental)
1554
1621
  - [Commands inside /bin](#commands-inside-bin)
1555
1622
  * [Buninu Browser (early-stage, experimental)](#buninu-browser-early-stage-experimental)
1623
+ * [Buninu Land (early-stage, experimental)](#buninu-land-early-stage-experimental)
1556
1624
  * [Archive tools and other examples](#archive-tools-and-other-examples)
1557
1625
  - [Optional chroot and native binaries](#optional-chroot-and-native-binaries)
1558
1626
  * [Debian and Chromium with casty](#debian-and-chromium-with-casty)
@@ -1606,8 +1674,8 @@ architecture under `native/<arch>/lib/`, and the built image redistributes
1606
1674
  several more. Each stays
1607
1675
  under its own terms, with platform license texts in [`LICENSES/`](LICENSES/).
1608
1676
 
1609
- The build also fetches four SHA-256-pinned npm releases and redistributes
1610
- them under `/usr/lib/node_modules`: `buninu-browser`, `@drxiaozhi/casty`,
1677
+ The build also fetches five SHA-256-pinned npm releases and redistributes
1678
+ them under `/usr/lib/node_modules`: `buninu-browser`, `buninu-land`, `@drxiaozhi/casty`,
1611
1679
  `@drxiaozhi/jspulse` and `@drxiaozhi/jspinyin`. Their license and notice files
1612
1680
  remain inside their package directories. Exact download URLs and hashes are
1613
1681
  in [`scripts/npm-packages.md`](scripts/npm-packages.md); versions, upstream
@@ -1627,9 +1695,10 @@ when redistributing the image.
1627
1695
  | Linux kernels and networking, storage, xHCI, USB and HID modules | GPL-2.0-only with the Linux syscall note | image only |
1628
1696
  | systemd EFI stub | LGPL-2.1-or-later | image only |
1629
1697
  | Bun | MIT, plus the licenses of what it statically links | image only |
1630
- | buninu-browser 0.2.2 | MIT for its own code; bundled components have their own licenses | npm download → image |
1698
+ | buninu-browser 0.2.3 | MIT for its own code; bundled components have their own licenses | npm download → image |
1699
+ | buninu-land 0.1.2 | MIT for its own code; bundled components retain their own licenses and notices | npm download → image |
1631
1700
  | wasmpeg / FFmpeg (`@wasmpeg/cpu` 1.0.1, bundled in buninu-browser) | LGPL-2.1-or-later, plus component notices; source archive and rebuild documentation retained | browser package → image |
1632
- | `@drxiaozhi/casty` 1.3.4 | MIT | npm download → image |
1701
+ | `@drxiaozhi/casty` 1.3.6 | MIT | npm download → image |
1633
1702
  | `@drxiaozhi/jspulse` 0.2.1 | LGPL-2.1-or-later, plus component notices | npm download → image |
1634
1703
  | `@drxiaozhi/jspinyin` 0.1.1 | MIT; hanzipinyin material under the Unlicense | npm download → image |
1635
1704
  | CanvasKit 0.41.1 (`initramfs/lib/canvaskit/`, Skia compiled to WebAssembly) | BSD-3-Clause (`LICENSES/BSD-3-Clause-Skia.txt`) | committed |
@@ -0,0 +1,26 @@
1
+ #!/bin/bun
2
+ // Keep the offline casty launcher outside the npm package so package updates
3
+ // preserve the distribution entry point.
4
+ import { resolve, join } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+
7
+ const root = resolve(import.meta.dir, "..");
8
+ const modules = join(root, "usr/lib/node_modules");
9
+ const browser = join(modules, "buninu-land");
10
+ const entry = join(browser, "index.js");
11
+ const { chooseFrontend } = await import(pathToFileURL(entry).href);
12
+ const args = process.argv.slice(2);
13
+ const choice = chooseFrontend(args);
14
+ const casty = choice.frontend === "casty";
15
+ const forwarded = casty ? choice.args : args;
16
+ // Bun consumes a leading separator after the script path; preserve Casty's
17
+ // own separator when --casty is followed directly by -- engine flags.
18
+ const runtimeArgs = forwarded[0] === "--" ? ["--", ...forwarded] : forwarded;
19
+ const child = Bun.spawn({
20
+ cmd: [process.execPath, casty ? join(modules, "@drxiaozhi/casty/index.js") : entry,
21
+ ...runtimeArgs],
22
+ env: casty ? { ...process.env, CASTY_BROWSER: join(browser, "compositor.js") } : process.env,
23
+ stdio: ["inherit", "inherit", "inherit"],
24
+ });
25
+ for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) process.on(signal, () => child.kill(signal));
26
+ process.exit(await child.exited);
@@ -10,6 +10,8 @@
10
10
 
11
11
  import { chmodSync, existsSync, mkdirSync, realpathSync, statSync, readFileSync, writeFileSync } from "node:fs";
12
12
  import { libc, cString, ptr, errno, strerror, Errno } from "../lib/dlopen.js";
13
+ import { dirname } from "node:path";
14
+ import { parseChrootArguments, resolveBindings, resolveGuestPath } from "../lib/chroot-options.js";
13
15
  import { showDocument } from "../lib/document.js";
14
16
 
15
17
  const MS = { RDONLY: 1n, NOSUID: 2n, NODEV: 4n, NOEXEC: 8n, BIND: 4096n, REC: 16384n, SLAVE: 1n << 19n };
@@ -23,27 +25,18 @@ const fail = (message, status = 125) => {
23
25
  const usage = () => {
24
26
  console.error(`Usage:
25
27
  chroot NEWROOT [COMMAND [ARGUMENT...]]
26
- chroot [-n] [-k] [-v] NEWROOT [COMMAND [ARGUMENT...]]
28
+ chroot [-n] [-k] [-v] [-b HOST[:GUEST]] [--shared-tmp] NEWROOT [COMMAND [ARGUMENT...]]
27
29
  chroot -h | --help full manual (chroot.md)`);
28
30
  process.exit(125);
29
31
  };
30
32
 
31
33
  // ------------------------------------------------------------- arguments --
32
34
 
33
- const options = { mount: true, keep: false, verbose: false };
34
- const positional = [];
35
- const argv = process.argv.slice(2);
36
- for (let index = 0; index < argv.length; index++) {
37
- const argument = argv[index];
38
- if (positional.length > 0) { positional.push(argument); continue; }
39
- if (argument === "--") { positional.push(...argv.slice(index + 1)); break; }
40
- if (argument === "-h" || argument === "--help") { await showDocument("chroot"); process.exit(0); }
41
- else if (argument === "-n" || argument === "--no-mount") options.mount = false;
42
- else if (argument === "-k" || argument === "--keep-mounts") options.keep = true;
43
- else if (argument === "-v" || argument === "--verbose") options.verbose = true;
44
- else if (argument.startsWith("-") && argument.length > 1) { console.error(`chroot: unknown option ${argument}`); usage(); }
45
- else positional.push(argument);
46
- }
35
+ let parsed;
36
+ try { parsed = parseChrootArguments(process.argv.slice(2)); }
37
+ catch (error) { fail(error.message); }
38
+ const { options, positional } = parsed;
39
+ if (parsed.help) { await showDocument("chroot"); process.exit(0); }
47
40
  if (positional.length === 0) usage();
48
41
 
49
42
  const [target, ...command] = positional;
@@ -55,6 +48,10 @@ try {
55
48
  fail(`cannot change root directory to ${target}: ${error.code === "ENOENT" ? "no such directory" : error.message}`);
56
49
  }
57
50
  if (root === "/") fail("refusing to chroot to /");
51
+ let bindings;
52
+ try { bindings = resolveBindings(options.binds); }
53
+ catch (error) { fail(`invalid bind: ${error.message}`); }
54
+
58
55
 
59
56
  const report = (message) => { if (options.verbose) console.error(`chroot: ${message}`); };
60
57
 
@@ -80,57 +77,39 @@ const made = [];
80
77
  // Prepares one mount. `inside` is the path within the new root. A target that
81
78
  // is already a mount point, or that cannot be created on a read-only root, is
82
79
  // left alone rather than treated as a failure: the command may still run.
83
- const prepare = ({ inside, source, type, flags = 0n, data, file = false }) => {
80
+ const prepare = ({ inside, source, type, flags = 0n, data, file = false, required = false }) => {
81
+ inside = resolveGuestPath(root, inside);
82
+ if (!required && bindings.some(bind => {
83
+ const destination = resolveGuestPath(root, bind.inside);
84
+ return inside === destination || inside.startsWith(destination + "/");
85
+ })) return;
86
+ if (required && made.includes(inside)) throw Error(`bind destination is already used by this invocation: ${inside}`);
84
87
  const point = `${root}${inside}`;
85
- if (mountPoints().includes(point)) {
88
+ if (!required && mountPoints().includes(point)) {
86
89
  report(`${inside} is already mounted`);
87
90
  return;
88
91
  }
89
92
  if (!existsSync(point)) {
90
93
  try {
91
- if (file) writeFileSync(point, "");
94
+ if (file) { mkdirSync(dirname(point), { recursive: true, mode: 0o755 }); writeFileSync(point, "", { flag: "wx" }); }
92
95
  else mkdirSync(point, { recursive: true, mode: 0o755 });
93
96
  } catch (error) {
97
+ if (required) throw Error(`cannot create ${inside}: ${error.message}`);
94
98
  report(`cannot create ${inside}: ${error.message}; skipped`);
95
99
  return;
96
100
  }
97
101
  }
98
102
  if (mountSyscall(source, point, type, flags, data) === -1) {
103
+ if (required) throw Error(`bind ${source} -> ${inside}: ${strerror(errno())}`);
99
104
  report(`mount ${inside}: ${strerror(errno())}; skipped`);
100
105
  return;
101
106
  }
102
107
  made.push(inside);
103
108
  report(`mounted ${inside}`);
104
- };
105
-
106
- if (options.mount) {
107
- prepare({ inside: "/proc", source: "proc", type: "proc", flags: MS.NOSUID | MS.NODEV | MS.NOEXEC });
108
- prepare({ inside: "/sys", source: "sysfs", type: "sysfs", flags: MS.NOSUID | MS.NODEV | MS.NOEXEC });
109
- // /dev is bound rather than mounted fresh so the devices, the pty
110
- // multiplexer and anything the host added are all there. The bind is then
111
- // made a slave: mounts appearing inside do not propagate back to the host,
112
- // and unmounting it later does not take the host's /dev with it.
113
- prepare({ inside: "/dev", source: "/dev", type: "none", flags: MS.BIND | MS.REC });
114
- if (made.includes("/dev")) {
115
- if (mountSyscall("none", `${root}/dev`, "none", MS.REC | MS.SLAVE) === -1) {
116
- report(`making /dev a slave mount: ${strerror(errno())}`);
117
- }
118
- // Only needed when the host has no /dev/pts of its own to bring along.
119
- if (!existsSync(`${root}/dev/pts/ptmx`)) {
120
- prepare({ inside: "/dev/pts", source: "devpts", type: "devpts", flags: MS.NOSUID | MS.NOEXEC, data: "gid=5,mode=620,ptmxmode=666" });
121
- }
109
+ if (required && !file && mountSyscall("none", point, "none", MS.REC | MS.SLAVE) === -1) {
110
+ throw Error(`making ${inside} a slave mount: ${strerror(errno())}`);
122
111
  }
123
- prepare({ inside: "/run", source: "tmpfs", type: "tmpfs", flags: MS.NOSUID | MS.NODEV, data: "mode=755" });
124
- prepare({ inside: "/tmp", source: "tmpfs", type: "tmpfs", flags: MS.NOSUID | MS.NODEV, data: "mode=1777" });
125
- // A bound file, so name resolution inside follows the host's configuration
126
- // and nothing inside the root is modified.
127
- if (existsSync("/etc/resolv.conf") && existsSync(`${root}/etc`)) {
128
-
129
- chmodSync(`/etc/resolv.conf`, 0o644);
130
-
131
- prepare({ inside: "/etc/resolv.conf", source: "/etc/resolv.conf", type: "none", flags: MS.BIND, file: true });
132
- }
133
- }
112
+ };
134
113
 
135
114
  // Mount points are recorded by their path inside the new root. Until
136
115
  // chroot(2) has happened they are reached through this prefix; afterwards
@@ -167,10 +146,52 @@ const cleanup = () => {
167
146
 
168
147
  process.on("exit", cleanup);
169
148
 
149
+ try {
150
+ if (options.mount) {
151
+ prepare({ inside: "/proc", source: "proc", type: "proc", flags: MS.NOSUID | MS.NODEV | MS.NOEXEC });
152
+ prepare({ inside: "/sys", source: "sysfs", type: "sysfs", flags: MS.NOSUID | MS.NODEV | MS.NOEXEC });
153
+ // /dev is bound rather than mounted fresh so the devices, the pty
154
+ // multiplexer and anything the host added are all there. The bind is then
155
+ // made a slave: mounts appearing inside do not propagate back to the host,
156
+ // and unmounting it later does not take the host's /dev with it.
157
+ prepare({ inside: "/dev", source: "/dev", type: "none", flags: MS.BIND | MS.REC });
158
+ if (made.includes("/dev")) {
159
+ if (mountSyscall("none", `${root}/dev`, "none", MS.REC | MS.SLAVE) === -1) {
160
+ report(`making /dev a slave mount: ${strerror(errno())}`);
161
+ }
162
+ // Only needed when the host has no /dev/pts of its own to bring along.
163
+ if (!existsSync(`${root}/dev/pts/ptmx`)) {
164
+ prepare({ inside: "/dev/pts", source: "devpts", type: "devpts", flags: MS.NOSUID | MS.NOEXEC, data: "gid=5,mode=620,ptmxmode=666" });
165
+ }
166
+ }
167
+ prepare({ inside: "/run", source: "tmpfs", type: "tmpfs", flags: MS.NOSUID | MS.NODEV, data: "mode=755" });
168
+ prepare({ inside: "/tmp", source: "tmpfs", type: "tmpfs", flags: MS.NOSUID | MS.NODEV, data: "mode=1777" });
169
+ // A bound file, so name resolution inside follows the host's configuration
170
+ // and nothing inside the root is modified.
171
+ if (existsSync("/etc/resolv.conf") && existsSync(`${root}/etc`)) {
172
+
173
+ chmodSync(`/etc/resolv.conf`, 0o644);
174
+
175
+ prepare({ inside: "/etc/resolv.conf", source: "/etc/resolv.conf", type: "none", flags: MS.BIND, file: true });
176
+ }
177
+ }
178
+
179
+ for (const binding of bindings) {
180
+ prepare({ ...binding, type: "none", flags: MS.BIND | (binding.file ? 0n : MS.REC), required: true });
181
+ }
182
+ } catch (error) {
183
+ // --keep-mounts applies to a prepared session, not a failed setup.
184
+ options.keep = false;
185
+ cleanup();
186
+ fail(error.message);
187
+ }
188
+
189
+
170
190
  // ----------------------------------------------------------------- enter --
171
191
 
172
192
  if (libc.symbols.chroot(ptr(cString(root))) === -1) {
173
193
  const code = errno();
194
+ options.keep = false;
174
195
  cleanup();
175
196
  fail(`cannot change root directory to ${target}: ${code === Errno.EPERM ? "must be superuser" : strerror(code)}`);
176
197
  }
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.21 - 2026-10-15
4
+
5
+ - Sync jsgotty to 1.1.16: Turn on pixel report
6
+
7
+ ## 0.4.20 - 2026-10-13
8
+
9
+ - Sync bunmsh to 0.4.0:
10
+ * Add a pure JavaScript awk fallback, file diff with line alignment, cmp,
11
+ uniq, expr, and egrep/fgrep aliases; extend sed and other utility builtins
12
+ for configure scripts and compiler builds.
13
+ * Improve compound commands, here-documents, parameter expansion, function
14
+ and loop control, descriptor redirection, and pipeline/subshell state
15
+ transfer for Autoconf and GCC bootstrap workloads.
16
+ * In `set -o posix` mode, use plain ls output and pass only exported variables
17
+ and command-prefix assignments to external programs. Default mode retains
18
+ ls icons and its existing environment behavior.
19
+ * Preserve the existing background-process behavior and stable
20
+ `Bun.sha.procs` indices. POSIX and awk compatibility remain partial; see
21
+ the bundled bunmsh PORTING.md for limitations.
22
+ - Sync jsgotty to 1.1.15: forward Kitty graphics to the terminal in `--client`
23
+ mode and avoid applying the corresponding cursor movement twice.
24
+
3
25
  ## 0.4.19 - 2026-10-12
4
26
 
5
27
  - Sync bunmsh to 0.3.11: more POSIX syntax
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "jsgotty",
3
- "version": "1.1.15",
3
+ "version": "1.1.16",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "jsgotty",
9
- "version": "1.1.15",
9
+ "version": "1.1.16",
10
10
  "dependencies": {
11
11
  "node-addon-api": "^7.1.1",
12
12
  "ws": "^8.18.3"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsgotty",
3
- "version": "1.1.15",
3
+ "version": "1.1.16",
4
4
  "description": "Share your terminal as a web application: A JavaScript rewrite of GoTTY",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -12530,6 +12530,7 @@
12530
12530
  (this.fontSizeOverride = fontSizeValue),
12531
12531
  (this.term = new r.Terminal({
12532
12532
  allowProposedApi: !0,
12533
+ windowOptions: { getWinSizePixels: true, getCellSizePixels: true },
12533
12534
  customGlyphs: !0,
12534
12535
  rescaleOverlappingGlyphs: !0,
12535
12536
  fontFamily:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "buninu",
3
- "version": "0.4.19",
3
+ "version": "0.4.21",
4
4
  "description": "Buninu is a portable, self-bootstrapping Unix-like userspace built on Bun that runs across operating systems",
5
5
  "type": "module",
6
6
  "main": "./bin/init.js",
@@ -0,0 +1,15 @@
1
+ // Report the content area in the same pixel units as SGR 1016, not fb margins.
2
+ export function attachGeometry({ term, renderer, reply }) {
3
+ term.options.windowOptions = { ...term.options.windowOptions, getWinSizePixels: true, getCellSizePixels: true };
4
+ return term.parser.registerCsiHandler({ final: 't' }, params => {
5
+ if (params[0] === 14 && params[1] !== 2) {
6
+ reply(`\x1b[4;${Math.round(term.rows * renderer.cellHeight)};${Math.round(term.cols * renderer.cellWidth)}t`);
7
+ return true;
8
+ }
9
+ if (params[0] === 16) {
10
+ reply(`\x1b[6;${Math.round(renderer.cellHeight)};${Math.round(renderer.cellWidth)}t`);
11
+ return true;
12
+ }
13
+ return false;
14
+ });
15
+ }
@@ -0,0 +1,10 @@
1
+ // Supply both coordinate systems: xterm selects cells (1006) or pixels (1016).
2
+ // Pixels are relative to the terminal content, excluding framebuffer margins.
3
+ export function terminalMouseEvent(report, renderer, button, action) {
4
+ const x = Math.floor(report.x - renderer.offsetX);
5
+ const y = Math.floor(report.y - renderer.offsetY);
6
+ return {
7
+ col: Math.floor(x / renderer.cellWidth), row: Math.floor(y / renderer.cellHeight),
8
+ x, y, button, action, ctrl: false, alt: false, shift: false,
9
+ };
10
+ }
@@ -21,6 +21,8 @@ import { Renderer, defaultTheme } from "./renderer.js";
21
21
  import { ImageStore } from "./images.js";
22
22
  import { openKeyboard, translateKeys } from "./input.js";
23
23
  import { claimVirtualConsole } from "./vt.js";
24
+ import { attachGeometry } from "./geometry.js";
25
+ import { terminalMouseEvent } from "./pointer-report.js";
24
26
  import { attachClipboard } from "./clipboard.js";
25
27
 
26
28
  const require = createRequire(import.meta.url);
@@ -160,6 +162,7 @@ export const createSession = ({
160
162
  });
161
163
  backend.onData(pump);
162
164
  term.onData((data) => backend.write(Buffer.from(data, "utf8")));
165
+ attachGeometry({ term, renderer, reply: text => backend.write(Buffer.from(text, "utf8")) });
163
166
  // OSC 52 copy and paste go straight to xclip; replies return to the program.
164
167
  // Without it (--no-clipboard) xterm.js ignores OSC 52 and nothing reaches xclip.
165
168
  if (clipboard) attachClipboard({ term, reply: (text) => backend.write(Buffer.from(text, "utf8")), onError });
@@ -181,7 +184,7 @@ export const createSession = ({
181
184
  // Turns a pointer report from mouse.js into the mouse sequences the
182
185
  // program asked for. xterm.js's CoreMouseService owns the protocol: it
183
186
  // knows which events the program enabled (DECSET 1000/1002/1003), encodes
184
- // them (SGR 1006 or the default form) and sends them through onData, so
187
+ // them (SGR 1006, pixel 1016, or the default form) and sends them through onData, so
185
188
  // nothing here builds an escape sequence. Reports arrive only while a
186
189
  // pointer is open, and this is the only place the terminal sees one.
187
190
  const CoreMouseButton = { LEFT: 0, MIDDLE: 1, RIGHT: 2, NONE: 3, WHEEL: 4 };
@@ -223,11 +226,9 @@ export const createSession = ({
223
226
  if (report.wheel) wheelScroll(report.wheel);
224
227
  return;
225
228
  }
226
- const column = Math.floor((report.x - renderer.offsetX) / renderer.cellWidth);
227
- const row = Math.floor((report.y - renderer.offsetY) / renderer.cellHeight);
228
229
  const send = (button, action) => {
229
230
  try {
230
- service.triggerMouseEvent({ col: column, row, button, action, ctrl: false, alt: false, shift: false });
231
+ service.triggerMouseEvent(terminalMouseEvent(report, renderer, button, action));
231
232
  } catch (error) {
232
233
  onError(error);
233
234
  }