feat(booter): hrpc allowlist parser, snapshot hints parity, shell pipefix, safer mv staging

- Add bare-os-hrpc-allowlist.js; wire stock bareOsHrpcRequest + bareOsHrpcAllowlistProbe;
  passthrough BARE_OS_HRPC_ALLOWLIST_JSON and operator env for snapshot/blind-relay/mirror/pear-doctor
- Merge BARE_OS_CORESTORE_SNAPSHOT_WORKFLOW_JSON into bareOsReadSnapshotHintsJson (match proc)
- Shell: pipefail runs all pipeline stages; aggregate first non-zero exit after assign prefixes
- mv: stage renames via vfs.resolveLogical so temp files stay in writable destination dir
- coreutils: POSIX-style split suffixes past zz; xargs doc for -P vs host subprocess
- identity-session: stable Error.code for no-account / passphrase failures
- Docs: KERNEL_CONTRACT, POSIX profile, handbook 5/7/9, kernel-extensions strict-boot table,
  env appendix, developer-guide + scripts README, protocol/booter CHANGELOGs; hrpc allowlist schema
- Tests: hrpc allowlist, pear_doctor schema 2, split suffix, pipefail pipeline; fix PLACEHOLDER_BASELINE link

Pretest: refreshed kernel bins, man.json, posix dashboard, bundle health, seeder parity
This commit is contained in:
Raven Scott
2026-04-05 01:31:03 -04:00
parent c64910d72e
commit 15209b4837
46 changed files with 1603 additions and 542 deletions
@@ -10,6 +10,8 @@ This chapter ties together **Holepunch `bare-*` packages**, the **Pear** host ru
2. **`ctx.bare` (host fallback)** — Unless **`BARE_OS_BARE_HOST_IMPORTS=0`**, the booter then **`import()`**s any manifest packages **still missing** after drive merge—typically native or Bare-only packages that could not be bundled, or when the image is older than the manifest. Set **`BARE_OS_BARE_HOST_IMPORTS=0`** for a **fully image-local** `ctx.bare` (no Pear host `node_modules` participation). Disable all `ctx.bare` with **`BARE_OS_BARE_MODULES=0`**. Manifest rows may include optional **`tier`** (**`core`** vs extended) and **`risk`** (**`low`**, **`medium`**, **`high`**) for distributor policy; the build honors **`tier`** via **`BARE_OS_BUNDLE_TIER`**. 2. **`ctx.bare` (host fallback)** — Unless **`BARE_OS_BARE_HOST_IMPORTS=0`**, the booter then **`import()`**s any manifest packages **still missing** after drive merge—typically native or Bare-only packages that could not be bundled, or when the image is older than the manifest. Set **`BARE_OS_BARE_HOST_IMPORTS=0`** for a **fully image-local** `ctx.bare` (no Pear host `node_modules` participation). Disable all `ctx.bare` with **`BARE_OS_BARE_MODULES=0`**. Manifest rows may include optional **`tier`** (**`core`** vs extended) and **`risk`** (**`low`**, **`medium`**, **`high`**) for distributor policy; the build honors **`tier`** via **`BARE_OS_BUNDLE_TIER`**.
**Boot cold path / stdlib budget:** the stock booter measures drive merge + host **`import()`** resolution for **`ctx.bare`** and sets **`BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS`** before the guest starts. Operators may set **`BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB`** to log **`boot-perf.json`** / stderr warnings when resolution exceeds the budget; combine with **`BARE_OS_BUNDLE_TIER=core`** (or a smaller manifest) to shrink cold I/O. Use **`node scripts/kernel-microbench.mjs`** for regression-shaped timings (not a literal Pear cold boot).
3. **The full mirror (discoverability)** — A local checkout of Holepunch repos (for example **`holepunchto_repos`** under your Pear tooling tree) lists on the order of **150+** repositories whose names start with **`bare-`**. Many are **native addons**, **platform-specific** (mobile, GUI, FFmpeg, …), or **developer tools**. The **manifest** can list them for `ctx.bare`, but only rows that bundle cleanly become real drive IIFEs; the rest rely on host import or stubs until you trim the manifest. 3. **The full mirror (discoverability)** — A local checkout of Holepunch repos (for example **`holepunchto_repos`** under your Pear tooling tree) lists on the order of **150+** repositories whose names start with **`bare-`**. Many are **native addons**, **platform-specific** (mobile, GUI, FFmpeg, …), or **developer tools**. The **manifest** can list them for `ctx.bare`, but only rows that bundle cleanly become real drive IIFEs; the rest rely on host import or stubs until you trim the manifest.
--- ---
+1 -1
View File
@@ -18,7 +18,7 @@ This project is **experimental research software**. APIs described here follow t
**Kernel source set:** [`docs/reference/kernel-extensions.md`](../docs/reference/kernel-extensions.md) — first-party paths (`kernel/init.js`, `kernel/lib/boot`, built `/bin`) vs vendored **`kernel/lib/bare/bundles`** (Holepunch IIFEs), CI allowlists, and seeder parity. Hand-authored code must stay free of incomplete markers; bundles are gated by **`verify-bundle-markers.mjs`**, **`verify-bundle-throws.mjs`** ( **`new Error` messages** with *not implemented* / abstract-base-class semantics — see [`docs/audit/bundle-throw-allowlist.json`](../docs/audit/bundle-throw-allowlist.json)), and **`sanitize-bare-bundles.mjs`**. Prefer shrinking the throw allowlist via upstream bundle refreshes over silent drift. **Kernel source set:** [`docs/reference/kernel-extensions.md`](../docs/reference/kernel-extensions.md) — first-party paths (`kernel/init.js`, `kernel/lib/boot`, built `/bin`) vs vendored **`kernel/lib/bare/bundles`** (Holepunch IIFEs), CI allowlists, and seeder parity. Hand-authored code must stay free of incomplete markers; bundles are gated by **`verify-bundle-markers.mjs`**, **`verify-bundle-throws.mjs`** ( **`new Error` messages** with *not implemented* / abstract-base-class semantics — see [`docs/audit/bundle-throw-allowlist.json`](../docs/audit/bundle-throw-allowlist.json)), and **`sanitize-bare-bundles.mjs`**. Prefer shrinking the throw allowlist via upstream bundle refreshes over silent drift.
**Local Holepunch clones:** run **`node scripts/sync-holepunch-clones.mjs`** to emit **`docs/audit/holepunch-clone-sync-report.json`** comparing **`bare-module-manifest.json`** names to optional checkouts under **`BARE_OS_HOLEPUNCH_CLONES_ROOT`** (default **`~/dev/pearcli/holepunch-repos/holepunchto_repos`**). **Local Holepunch mirror:** run **`node scripts/sync-holepunch-clones.mjs`** to emit **`docs/audit/holepunch-clone-sync-report.json`** comparing manifest package names to optional checkouts under **`BARE_OS_HOLEPUNCH_CLONES_ROOT`** (default **`~/dev/pearcli/holepunch-repos/holepunchto_repos`**). Root **`pretest`** runs **`node scripts/verify-holepunch-clone-drift.mjs`** against basenames listed in **`docs/audit/holepunch-drift-repos.json`** (empty **`repos[]`** = no-op). Regenerate the maximal npm catalog with **`node scripts/gen-bare-holepunch-catalog.mjs`** (or **`npm run gen:bare-catalog`**), then **`npm run sync:bare-manifest`** — see [scripts/README.md](../scripts/README.md).
--- ---
+1 -1
View File
@@ -68,7 +68,7 @@ Shared error classes (stable `code` field): [`packages/bare-os-booter/lib/bare-o
## Seed RPC and hrpc bridges ## Seed RPC and hrpc bridges
- **Seed RPC** (`bare_os.*` methods on the seeder wire): [`packages/bare-os-protocol/lib/channel.js`](../../packages/bare-os-protocol/lib/channel.js) answers only methods listed in [`seed-rpc-methods.js`](../../packages/bare-os-protocol/lib/seed-rpc-methods.js); unknown names return **`bare_os.rpc_unknown_method`** (default deny). Boot policy may add **`denySeedRpcMethods`** / env **`BARE_OS_BOOT_POLICY_DENY_SEED_RPC_METHODS`** so the stock booter skips selected calls. - **Seed RPC** (`bare_os.*` methods on the seeder wire): [`packages/bare-os-protocol/lib/channel.js`](../../packages/bare-os-protocol/lib/channel.js) answers only methods listed in [`seed-rpc-methods.js`](../../packages/bare-os-protocol/lib/seed-rpc-methods.js); unknown names return **`bare_os.rpc_unknown_method`** (default deny). Boot policy may add **`denySeedRpcMethods`** / env **`BARE_OS_BOOT_POLICY_DENY_SEED_RPC_METHODS`** so the stock booter skips selected calls.
- **hrpc** (`ctx.bareOsHrpcRequest`): the stock booter implementation validates inputs, enforces optional **`BARE_OS_HRPC_ALLOWLIST_JSON`**, and serves a built-in route table (**`kernel.ping`**, **`kernel.capabilities`**, **`vfs.readText`**, **`bare_os.echo`**, **`bare_os.disk_os_hints`** — the last mirrors the disk.os RPC hint JSON). **`process.emit('bare-os:hrpc-request', …)`** runs for unsupported routes only when **`BARE_OS_HRPC_EMIT_UNLISTED`** is **`1`** / **`true`**. Set **`BARE_OS_HRPC_AUDIT`** to append tamper-evident audit rows for attempts (via **`bareOsAuditChainLinkAppend`**). Treat new routes as security-sensitive: extend only with explicit allowlist semantics and tests. - **hrpc** (`ctx.bareOsHrpcRequest`): the stock booter implementation validates inputs, enforces optional **`BARE_OS_HRPC_ALLOWLIST_JSON`** (JSON **array** of **`"service.method"`** strings, or **object** whose **keys** are route names and values are truthy — see [`docs/schemas/bare-os-hrpc-allowlist.schema.json`](../schemas/bare-os-hrpc-allowlist.schema.json); wildcards **`"*"`**, **`"kernel.*"`**, etc.), and serves a built-in route table (**`kernel.ping`**, **`kernel.capabilities`**, **`vfs.readText`**, **`bare_os.echo`**, **`bare_os.disk_os_hints`** — the last mirrors the disk.os RPC hint JSON). **Deny-by-default:** any **`service.method`** not in the stock table throws **`bareOsHrpcRequest: unsupported route …`** unless the host replaces **`ctx.bareOsHrpcRequest`** or **`BARE_OS_HRPC_EMIT_UNLISTED`** is **`1`** / **`true`** (then **`process.emit('bare-os:hrpc-request', …)`** fires for unlisted routes). Set **`BARE_OS_HRPC_AUDIT`** to append tamper-evident audit rows for attempts (via **`bareOsAuditChainLinkAppend`**). Treat new routes as security-sensitive: extend only with explicit allowlist semantics and tests.
## Related docs ## Related docs
+2 -2
View File
@@ -18,7 +18,7 @@ This document is the **normative contract** for how closely the stock Bare OS ke
Bare OS does **not** expose a C ABI. The following **observability contracts** stand in for “system calls”: Bare OS does **not** expose a C ABI. The following **observability contracts** stand in for “system calls”:
- **`/proc/bare_os/syscalls.json`** — Declares **fd model**, **signal model**, **errno hints**, **operation detail**, **`posixXsh`**, **`socketMsgSurface`**, and related adjuncts (schema **8** in stock builds; see [`docs/reference/posix-compliance-matrix.json`](../reference/posix-compliance-matrix.json)). **`ops`** lists invocable **`ctx.bareOsSyscall`** names; **`opsDetail`** also carries **POSIX.1 XSH** logical names (**`open`**, **`close`**, **`read`**, **`write`**, **`readv`**, **`writev`**, **`getsockopt`**, **`setsockopt`**, **`lseek`**, **`pipe`**, **`dup`**, **`dup2`**, **`fcntl`**, **`poll`**, **`select`**, **`umask`**, and **socket family** probes) with **`posixAlignment`** (**`simulated`**, **`partial`**, **`ENOTSUP`**) and **`mapsTo`** for traceability. The **`posixXsh`** object summarizes those XSH names (via **`bareOsPosixXshOpsCsv()`**). **`socketMsgSurface`** (schema **2**) documents **`sendmsg`** / **`recvmsg`**: with **`BARE_OS_POSIX_SOCKET_FD_BRIDGE`** and **`SOCK_DGRAM`**, **`sendmsg`** flattens bounded **iovec** lists into one datagram and **`recvmsg`** returns **`buf`** plus **`msgHdr.name`** from **`rinfo`**; ancillary control messages and scatter **`recvmsg`** remain **`ENOTSUP`**. **`fcntl`** supports **`F_GETFL`** / **`F_SETFL`** (Linux-shaped **`O_APPEND`** **`0x400`**, **`O_NONBLOCK`** **`0x800`**) and **cooperative advisory locks** via **`F_GETLK`** / **`F_SETLK`** / **`F_SETLKW`** using **`args.path`** (absolute) or **`args.fd`** whose logical target is an absolute path; contended **`F_SETLK`** returns **`EAGAIN`**. **`F_SETLKW`** also returns **`EAGAIN`** by default; with **`BARE_OS_POSIX_FCNTL_BLOCKING_WAIT`**, it **awaits** the lock up to **`BARE_OS_FCNTL_LOCK_WAIT_MS_MAX`** (default **30000**, max **300000**) then **`ETIMEDOUT`**. Unknown FDs yield **`EBADF`**. **`readv`** / **`writev`** perform bounded scatter/gather on **`BARE_OS_POSIX_FD_SIM`** pipe read/write ends. **`poll`** / **`select`** share the same logical FD readiness probe when **`BARE_OS_POSIX_FD_SIM`** is enabled; with **`BARE_OS_POSIX_SOCKET_FD_BRIDGE=1`**, bridged **datagram** fds participate (**`SOCK_DGRAM`** via **`bareDgram`** when merged) with bounded **`recv`** / **`recvfrom`** queues (**`BARE_OS_POSIX_DGRAM_RECVQ_MAX`**, **`BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX`**). **Socket-shaped** syscalls default to **`ENOSYS`** / **`ENOTSUP`**; with **`BARE_OS_POSIX_SOCKET_FD_BRIDGE=1`**, **`socket`** + **`connect`** may use **`ctx.bare.bareTcp.Socket`** (**`SOCK_STREAM`**) or **`bareDgram`** (**`SOCK_DGRAM`**) when merged. The stock booter **caches** this JSON until warm read-cache invalidation. - **`/proc/bare_os/syscalls.json`** — Declares **fd model**, **signal model**, **errno hints**, **operation detail**, **`posixXsh`**, **`socketMsgSurface`**, and related adjuncts (schema **8** in stock builds; see [`docs/reference/posix-compliance-matrix.json`](../reference/posix-compliance-matrix.json)). **`ops`** lists invocable **`ctx.bareOsSyscall`** names; **`opsDetail`** also carries **POSIX.1 XSH** logical names (**`open`**, **`close`**, **`read`**, **`write`**, **`readv`**, **`writev`**, **`getsockopt`**, **`setsockopt`**, **`lseek`**, **`pipe`**, **`dup`**, **`dup2`**, **`fcntl`**, **`poll`**, **`select`**, **`umask`**, and **socket family** probes) with **`posixAlignment`** (**`simulated`**, **`partial`**, **`ENOTSUP`**) and **`mapsTo`** for traceability. The **`posixXsh`** object summarizes those XSH names (via **`bareOsPosixXshOpsCsv()`**). **`socketMsgSurface`** (schema **3**) documents **`sendmsg`** / **`recvmsg`** on the bridge: bounded **iovec** flattening for datagram and stream paths; non-empty ancillary **`cmsgs`/`control`/`controllen`/`msgHdr.*` on `sendmsg`** **`ENOTSUP`** + structured **`ancillaryReject`**; **`recvmsg`** **`controllen`** **0**. **`fcntl`** supports **`F_GETFL`** / **`F_SETFL`** (Linux-shaped **`O_APPEND`** **`0x400`**, **`O_NONBLOCK`** **`0x800`**) and **cooperative advisory locks** via **`F_GETLK`** / **`F_SETLK`** / **`F_SETLKW`** using **`args.path`** (absolute) or **`args.fd`** whose logical target is an absolute path; contended **`F_SETLK`** returns **`EAGAIN`**. **`F_SETLKW`** also returns **`EAGAIN`** by default; with **`BARE_OS_POSIX_FCNTL_BLOCKING_WAIT`**, waiters are queued **FIFO per lock path** until the lock is free or **`BARE_OS_FCNTL_LOCK_WAIT_MS_MAX`** elapses (**`ETIMEDOUT`**; default **30000** ms, max **300000**). There is **no** cross-path global fairness and **no** host deadlock detection. Unknown FDs yield **`EBADF`**. **`readv`** / **`writev`** perform bounded scatter/gather on **`BARE_OS_POSIX_FD_SIM`** pipe read/write ends. **`poll`** / **`select`** share the same logical FD readiness probe when **`BARE_OS_POSIX_FD_SIM`** is enabled; with **`BARE_OS_POSIX_SOCKET_FD_BRIDGE=1`**, bridged **datagram** fds participate (**`SOCK_DGRAM`** via **`bareDgram`** when merged) with bounded **`recv`** / **`recvfrom`** queues (**`BARE_OS_POSIX_DGRAM_RECVQ_MAX`**, **`BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX`**); passive **`SOCK_STREAM`** uses **`bind`/`listen`/`accept`** when **`bareTcp.Server`** is available. **Socket-shaped** syscalls default to **`ENOSYS`** / **`ENOTSUP`**; with **`BARE_OS_POSIX_SOCKET_FD_BRIDGE=1`**, **`socket`** + **`connect`** may use **`ctx.bare.bareTcp.Socket`** (**`SOCK_STREAM`**) or **`bareDgram`** (**`SOCK_DGRAM`**) when merged. The stock booter **caches** this JSON until warm read-cache invalidation.
- **`/proc/bare_os/process_table.json`** — **PGID** / **SID**-style fields, **`parentName`** (from **`ppid`**), **signal routing**, and initd binding for the **logical** process table (not host PIDs). - **`/proc/bare_os/process_table.json`** — **PGID** / **SID**-style fields, **`parentName`** (from **`ppid`**), **signal routing**, and initd binding for the **logical** process table (not host PIDs).
**Explicit non-goals** **Explicit non-goals**
@@ -53,7 +53,7 @@ Utilities are **Issue 7inspired** JavaScript implementations. High-traffic to
Two logical drives (**system** + **personal**) form one namespace; **`.bareos_empty`** marks empty directories. Synthetic trees: **`/proc`**, **`/sys`**, **`/run`**, **`/dev`**, session **`/tmp`**. **`/dev/shm/<name>`** holds **in-memory** named byte segments (not host **`shm_open`**); names match **`^[a-zA-Z0-9._-]{1,128}$`**. Optional **`/mirror/aux*`** for auxiliary read-only drives. Two logical drives (**system** + **personal**) form one namespace; **`.bareos_empty`** marks empty directories. Synthetic trees: **`/proc`**, **`/sys`**, **`/run`**, **`/dev`**, session **`/tmp`**. **`/dev/shm/<name>`** holds **in-memory** named byte segments (not host **`shm_open`**); names match **`^[a-zA-Z0-9._-]{1,128}$`**. Optional **`/mirror/aux*`** for auxiliary read-only drives.
**Rename:** No atomic cross-drive **`rename`**; **`mv`** implements copy + remove where needed (handbook ch.9). **Rename:** No atomic cross-drive **`rename`**; **`mv`** implements copy + remove where needed (handbook ch.9). For a **single regular file** to a non-directory destination, **`/bin/mv`** stages bytes under a unique **`.bare-os-mv-tmp.*`** name in the **resolved destination directory** (same folder as the target after **`vfs.resolveLogical`**), writes the final name, removes the staging entry, then unlinks the source so a failed final write leaves the source path intact (best-effort staging cleanup).
**`pathconf` / `getconf`:** Live **`getconf _PC_* /path`** delegates to **`ctx.bareOsPathconf`**. Union read prefixes (**`BARE_OS_VFS_UNION_PREFIXES`**) and read-only **mirror** paths (**`/mirror/…`**) adjust documented **`_PC_NO_TRUNC`** and **`_PC_CHOWN_RESTRICTED`** hints (not a certifiable pathconf implementation). **`pathconf` / `getconf`:** Live **`getconf _PC_* /path`** delegates to **`ctx.bareOsPathconf`**. Union read prefixes (**`BARE_OS_VFS_UNION_PREFIXES`**) and read-only **mirror** paths (**`/mirror/…`**) adjust documented **`_PC_NO_TRUNC`** and **`_PC_CHOWN_RESTRICTED`** hints (not a certifiable pathconf implementation).
+1 -1
View File
@@ -33,7 +33,7 @@ This document classifies incomplete surfaces as of the kernel hardening pass. It
| Item | Location | Notes | | Item | Location | Notes |
| ---------------------------- | --------------------------- | ----- | | ---------------------------- | --------------------------- | ----- |
| ~~`gen-ctx-client-stub.mjs`~~**`gen-ctx-client-helper.mjs`** | `scripts/` | Renamed; generates TS client version constant aligned with **`BARE_OS_CTX_API_VERSION`**. | | ~~`gen-ctx-client-stub.mjs`~~**`gen-ctx-client-helper.mjs`** | `scripts/` | Renamed; generates TS client version constant aligned with **`BARE_OS_CTX_API_VERSION`**. |
| Man / reference “placeholder” prose | `docs/`, `kernel/share/man/` | Tracked for alignment with implemented behavior. | | Man / reference “placeholder” prose | `docs/`, `kernel/share/man/` | **Closed for stock tree:** `node scripts/verify-man-coverage.mjs` gates **146** Tier-1 commands; regenerate merged man DB with **`npm run build -w bare-os-coreutils`** when pages change. Narrative alignment: [handbook ch.9 §5](../../handbook/09-posix-utilities-shell-and-vfs.md#5-bin-utilities-catalog). |
## Extension multisig gate (stock kernel) ## Extension multisig gate (stock kernel)
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"schemaVersion": 1, "schemaVersion": 1,
"generatedAt": "2026-04-05T05:06:01.522Z", "generatedAt": "2026-04-05T05:30:46.141Z",
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json", "normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
"buildTool": "packages/bare-os-bare-libs/build.mjs", "buildTool": "packages/bare-os-bare-libs/build.mjs",
"bundles": [ "bundles": [
+4 -2
View File
@@ -14,7 +14,7 @@ Single place to compare **protocol**, **booter `ctx` API**, **feature-bit docume
## Version artifacts ## Version artifacts
**`bareOsCtxApiVersion`** (current stock: **`1.44.0`**) — Defined in [`packages/bare-os-booter/lib/bare-os-ctx-api.js`](../../packages/bare-os-booter/lib/bare-os-ctx-api.js). This is the semver string for the documented **`ctx`** contract; bump it when stable guest-visible behavior changes. **`bareOsCtxApiVersion`** (current stock: **`1.45.0`**) — Defined in [`packages/bare-os-booter/lib/bare-os-ctx-api.js`](../../packages/bare-os-booter/lib/bare-os-ctx-api.js). This is the semver string for the documented **`ctx`** contract; bump it when stable guest-visible behavior changes.
**`BARE_OS_KERNEL_FEATURE_BITS_DOC`** (current stock: **`15`**) — Exported from [`packages/bare-os-protocol/lib/kernel-feature-bits.js`](../../packages/bare-os-protocol/lib/kernel-feature-bits.js). It versions the feature-bit documentation and related governance; keep it aligned with [`developer-guide/adr/001-kernel-feature-bits-governance.md`](../../developer-guide/adr/001-kernel-feature-bits-governance.md). **`BARE_OS_KERNEL_FEATURE_BITS_DOC`** (current stock: **`15`**) — Exported from [`packages/bare-os-protocol/lib/kernel-feature-bits.js`](../../packages/bare-os-protocol/lib/kernel-feature-bits.js). It versions the feature-bit documentation and related governance; keep it aligned with [`developer-guide/adr/001-kernel-feature-bits-governance.md`](../../developer-guide/adr/001-kernel-feature-bits-governance.md).
@@ -26,7 +26,9 @@ Single place to compare **protocol**, **booter `ctx` API**, **feature-bit docume
**POSIX-like profile****`BARE_OS_POSIX_PROFILE_VERSION`** (**`1.0.9`**) and **`BARE_OS_POSIX_PROFILE_ID`** (**`bare-os-posix-like`**) in [`bare-os-protocol/lib/bare-os-posix-profile.js`](../../packages/bare-os-protocol/lib/bare-os-posix-profile.js). Surfaced under **`/proc/bare_os_features`** as **`capabilitySurface.posixProfile`** and in **`/proc/bare_os/syscalls.json`**. **POSIX-like profile****`BARE_OS_POSIX_PROFILE_VERSION`** (**`1.0.9`**) and **`BARE_OS_POSIX_PROFILE_ID`** (**`bare-os-posix-like`**) in [`bare-os-protocol/lib/bare-os-posix-profile.js`](../../packages/bare-os-protocol/lib/bare-os-posix-profile.js). Surfaced under **`/proc/bare_os_features`** as **`capabilitySurface.posixProfile`** and in **`/proc/bare_os/syscalls.json`**.
**`/proc/bare_os/syscalls.json`** — Schema **8** documents cooperative **`fcntl`** advisory locks (optional **`BARE_OS_POSIX_FCNTL_BLOCKING_WAIT`** for **`F_SETLKW`**-shaped waits), optional **`BARE_OS_POSIX_SOCKET_FD_BRIDGE`** **`socket`/`connect`** (**`SOCK_STREAM`** via **`bareTcp`**, **`SOCK_DGRAM`** via **`bareDgram`** when merged) with bounded **`send`/`sendmsg`/`recv`/`recvfrom`/`recvmsg`** on bridged datagram fds (**`BARE_OS_POSIX_DGRAM_RECVQ_MAX`**, **`BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX`**), **`socketMsgSurface`** schema **2** (**`sendmsg`/`recvmsg`** partial on bridge; ancillary CMSGS **`ENOTSUP`**), and retains socket-family **probes** plus **`posixXsh`**. Earlier schemas added **`fdModel`**, **`signalModel`**, **`opsDetail`**, **`errnoHints`**, and **`posixProfile`**. The stock booter **caches** the JSON text until **`vfs.bareOsClearWarmReadCaches()`** / **`ctx.bareOsInvalidateWarmReadCaches()`** (same invalidation path as **`/bin`** warm cache; **`boot/init.js`** and **`lib/init/**` batch puts also invalidate). Example payload: [`kernel/etc/bare-os/syscalls.example.json`](../../kernel/etc/bare-os/syscalls.example.json); JSON Schema: [`docs/schemas/bare-os-syscalls.schema.json`](../schemas/bare-os-syscalls.schema.json). **`/proc/bare_os/syscalls.json`** — Schema **8** (see also [handbook ch.9 §2.3](../../handbook/09-posix-utilities-shell-and-vfs.md#23-pseudo-proc-sys-run-dev-and-session-tmp)) documents cooperative **`fcntl`** advisory locks (optional **`BARE_OS_POSIX_FCNTL_BLOCKING_WAIT`** for **`F_SETLKW`**-shaped waits), optional **`BARE_OS_POSIX_SOCKET_FD_BRIDGE`** **`socket`/`connect`** (**`SOCK_STREAM`** via **`bareTcp`**, **`SOCK_DGRAM`** via **`bareDgram`** when merged) with bounded **`send`/`sendmsg`/`recv`/`recvfrom`/`recvmsg`** on bridged datagram fds (**`BARE_OS_POSIX_DGRAM_RECVQ_MAX`**, **`BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX`**), **`socketMsgSurface`** schema **3** (**`sendmsg`/`recvmsg`** partial on bridge; non-empty ancillary on **`sendmsg`** → **`ENOTSUP`** + **`ancillaryReject`**; **`recvmsg`** **`controllen` 0**), and retains socket-family **probes** plus **`posixXsh`**. Earlier schemas added **`fdModel`**, **`signalModel`**, **`opsDetail`**, **`errnoHints`**, and **`posixProfile`**. The stock booter **caches** the JSON text until **`vfs.bareOsClearWarmReadCaches()`** / **`ctx.bareOsInvalidateWarmReadCaches()`** (same invalidation path as **`/bin`** warm cache; **`boot/init.js`** and **`lib/init/**` batch puts also invalidate). Example payload: [`kernel/etc/bare-os/syscalls.example.json`](../../kernel/etc/bare-os/syscalls.example.json); JSON Schema: [`docs/schemas/bare-os-syscalls.schema.json`](../schemas/bare-os-syscalls.schema.json).
**`/proc/bare_os/process_table.json`** — Schema **7** (see **`fdModel.processTableSchema`** inside **`syscalls.json`** and [handbook ch.9 §2.3](../../handbook/09-posix-utilities-shell-and-vfs.md#23-pseudo-proc-sys-run-dev-and-session-tmp)); documents logical jobs, PGID/SID-style fields, initd binding, and signal routing.
**Boot policy pins** — [`kernel/etc/bare-os/boot.policy.example.json`](../../kernel/etc/bare-os/boot.policy.example.json) shows **`extensionSignerPinsV3`**, **`extensionSignerPinsV4`**, and **`kernelExtensionHashPins`** for **`kernel.ext.d`** governance, plus semver gates (**`requireCtxApiMin`**, **`requireBooterSemver`**, **`requireProtocolPackageMin`**, …). Keep this file aligned with [`docs/schemas/boot.policy.schema.json`](../schemas/boot.policy.schema.json) when adding fields. **Boot policy pins** — [`kernel/etc/bare-os/boot.policy.example.json`](../../kernel/etc/bare-os/boot.policy.example.json) shows **`extensionSignerPinsV3`**, **`extensionSignerPinsV4`**, and **`kernelExtensionHashPins`** for **`kernel.ext.d`** governance, plus semver gates (**`requireCtxApiMin`**, **`requireBooterSemver`**, **`requireProtocolPackageMin`**, …). Keep this file aligned with [`docs/schemas/boot.policy.schema.json`](../schemas/boot.policy.schema.json) when adding fields.
@@ -1,7 +1,7 @@
// Auto-generated by scripts/gen-ctx-client-helper.mjs — do not edit by hand. // Auto-generated by scripts/gen-ctx-client-helper.mjs — do not edit by hand.
/** Canonical `ctx` API semver from `packages/bare-os-booter/lib/bare-os-ctx-api.js`. */ /** Canonical `ctx` API semver from `packages/bare-os-booter/lib/bare-os-ctx-api.js`. */
export const BARE_OS_CTX_API_CLIENT_VERSION = '1.44.0' as const export const BARE_OS_CTX_API_CLIENT_VERSION = '1.45.0' as const
/** Relative path to the hand-maintained TypeScript contract (schema source of truth). */ /** Relative path to the hand-maintained TypeScript contract (schema source of truth). */
export const BARE_OS_CTX_DTS_SOURCE = 'packages/bare-os-booter/lib/bare-os-ctx.d.ts' as const export const BARE_OS_CTX_DTS_SOURCE = 'packages/bare-os-booter/lib/bare-os-ctx.d.ts' as const
@@ -20,6 +20,12 @@ The list below is one **bullet per variable** in the form **name — component
- `BARE_OS_KERNEL_ROOT` — Seeder — Absolute path to kernel tree (default: `repo/kernel`) - `BARE_OS_KERNEL_ROOT` — Seeder — Absolute path to kernel tree (default: `repo/kernel`)
- `BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG` — Seeder — Optional tag string; when set (and **`BARE_OS_SEED_SNAPSHOT_HINTS_JSON`** is unset), the seeder builds **`snapshotHintsJson`** for **`bare_os.snapshot_hints`** so the booter can surface it under **`/proc/bare_os/snapshot_hints.json`** after RPC. - `BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG` — Seeder — Optional tag string; when set (and **`BARE_OS_SEED_SNAPSHOT_HINTS_JSON`** is unset), the seeder builds **`snapshotHintsJson`** for **`bare_os.snapshot_hints`** so the booter can surface it under **`/proc/bare_os/snapshot_hints.json`** after RPC.
- `BARE_OS_SEED_SNAPSHOT_HINTS_JSON` — Seeder — Optional JSON string; when set, passed verbatim as **`snapshotHintsJson`** (wins over **`BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG`**). - `BARE_OS_SEED_SNAPSHOT_HINTS_JSON` — Seeder — Optional JSON string; when set, passed verbatim as **`snapshotHintsJson`** (wins over **`BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG`**).
- `BARE_OS_CORESTORE_SNAPSHOT_WORKFLOW_JSON` — Booter — Optional JSON merged into **`/proc/bare_os/snapshot_hints.json`** and **`ctx.bareOsReadSnapshotHintsJson()`** as **`corestoreSnapshotWorkflow`** (keep shape aligned with seeder **`snapshot_hints`** / corestore-snapshot tooling; parse errors set **`corestoreSnapshotWorkflowParseError`**).
- `BARE_OS_HRPC_ALLOWLIST_JSON` — Booter — Optional allowlist for stock **`ctx.bareOsHrpcRequest`**: JSON **array** of **`service.method`** strings or **object** with route keys and truthy values; wildcards **`"*"`** / **`kernel.*`** supported. Invalid JSON fails the first hrpc call. Schema: [`docs/schemas/bare-os-hrpc-allowlist.schema.json`](../schemas/bare-os-hrpc-allowlist.schema.json).
- `BARE_OS_BLIND_RELAY_TOPOLOGY_JSON` — Booter — Optional JSON summarized under **`/proc/bare_os/swarm.json`** → **`blindRelayTopology`** (PII-free operator sketch).
- `BARE_OS_MIRROR_DRIVE_COMPOSITION_HINT_JSON` — Booter — Optional JSON summarized under **`/proc/bare_os/replication`** → **`mirrorDriveCompositionHint`** (mirror-drivestyle aux composition hints).
- `BARE_OS_REPLICATION_PLAN_JSON` — Booter — Optional JSON merged into **`/proc/bare_os/replication`** as **`guestReplicationPlan`** (operator warm-replication hints).
- `BARE_OS_PEAR_DOCTOR_STATE_JSON` / `BARE_OS_PEAR_INSPECT_PROBE` / `BARE_OS_PEAR_DOCTOR_MODULE` — Booter — Feed **`/proc/bare_os_pear_doctor_state.json`** (**schema 2**) for pear-runtime / pear-inspect parity (**`pearDoctorModuleHint`**, **`pearInspectProbe`**, **`runtimeVersion`** via **`BARE_OS_PEAR_RUNTIME_VERSION`**).
- `BARE_OS_HOST_DATA` — paths — Base directory for host state (default `~/.bare-os`; Corestore dirs live under `corestore/`) - `BARE_OS_HOST_DATA` — paths — Base directory for host state (default `~/.bare-os`; Corestore dirs live under `corestore/`)
- `BARE_OS_SEED_STORE` — Seeder — Corestore directory (default: `~/.bare-os/corestore/seeder`) - `BARE_OS_SEED_STORE` — Seeder — Corestore directory (default: `~/.bare-os/corestore/seeder`)
- `BARE_OS_BOOT_STORE` — Booter — Corestore for boot side (default: `~/.bare-os/corestore/booter`) - `BARE_OS_BOOT_STORE` — Booter — Corestore for boot side (default: `~/.bare-os/corestore/booter`)
@@ -147,9 +153,10 @@ The list below is one **bullet per variable** in the form **name — component
- `BARE_OS_POSIX_FD_SIM_MAX_BYTES` — Booter — Max buffered bytes per simulated pipe pair (default **`1048576`**, hard cap **16 MiB**). - `BARE_OS_POSIX_FD_SIM_MAX_BYTES` — Booter — Max buffered bytes per simulated pipe pair (default **`1048576`**, hard cap **16 MiB**).
- `BARE_OS_POSIX_FCNTL_BLOCKING_WAIT` — Booter — When **`1`** / **`true`** / **`yes`**, **`F_SETLKW`** on cooperative advisory locks **waits** (FIFO queue) until the lock is free or **`BARE_OS_FCNTL_LOCK_WAIT_MS_MAX`** elapses (**`ETIMEDOUT`**). - `BARE_OS_POSIX_FCNTL_BLOCKING_WAIT` — Booter — When **`1`** / **`true`** / **`yes`**, **`F_SETLKW`** on cooperative advisory locks **waits** (FIFO queue) until the lock is free or **`BARE_OS_FCNTL_LOCK_WAIT_MS_MAX`** elapses (**`ETIMEDOUT`**).
- `BARE_OS_FCNTL_LOCK_WAIT_MS_MAX` — Booter — Upper bound in milliseconds for **`F_SETLKW`** blocking wait (default **`30000`**, hard cap **`300000`**). - `BARE_OS_FCNTL_LOCK_WAIT_MS_MAX` — Booter — Upper bound in milliseconds for **`F_SETLKW`** blocking wait (default **`30000`**, hard cap **`300000`**).
- `BARE_OS_POSIX_SOCKET_FD_BRIDGE` — Booter — When **`1`** / **`true`**, **`ctx.bareOsSyscall('socket')`** allocates a logical bridge fd; **`SOCK_STREAM`** **`connect`** may use **`ctx.bare.bareTcp.Socket`** when **`bare-tcp`** is merged; **`SOCK_DGRAM`** uses **`ctx.bare.bareDgram`** when merged, with **`send`**, **`recv`**, **`recvfrom`**, bounded **`sendmsg`/`recvmsg`** (flattened iovs on the bridge path), and **`poll`/`select`** readiness on the logical fd. See **`socketMsgSurface`** in **`/proc/bare_os/syscalls.json`** for the advertised surface. - `BARE_OS_POSIX_SOCKET_FD_BRIDGE` — Booter — When **`1`** / **`true`**, **`ctx.bareOsSyscall('socket')`** allocates a logical bridge fd; **`SOCK_STREAM`** **`connect`** may use **`ctx.bare.bareTcp.Socket`** when **`bare-tcp`** is merged; **`SOCK_DGRAM`** uses **`ctx.bare.bareDgram`** when merged, with **`send`**, **`recv`**, **`recvfrom`**, bounded **`sendmsg`/`recvmsg`** (flattened iovs on the bridge path; non-empty ancillary **`cmsgs`/`control`/`controllen`/`msgHdr.*` on **`sendmsg`** → **`ENOTSUP`** + **`ancillaryReject`** per **`socketMsgSurface` schema 3**), and **`poll`/`select`** readiness on the logical fd. See **`socketMsgSurface`** in **`/proc/bare_os/syscalls.json`** for the advertised surface.
- `BARE_OS_POSIX_DGRAM_RECVQ_MAX` — Booter — Max queued datagrams per bridged UDP fd (bounded **`recv`** path); default and caps are enforced in the booter. - `BARE_OS_POSIX_DGRAM_RECVQ_MAX` — Booter — Max queued datagrams per bridged UDP fd (bounded **`recv`** path); default and caps are enforced in the booter. Also bounds per-chunk queue depth for **accepted** SOCK_STREAM bridge fds (**`tcpRecvQueue`**).
- `BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX` — Booter — Optional blocking **`recv`** wait cap (ms) for bridged UDP fds before **`EAGAIN`**-shaped timeout notes. - `BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX` — Booter — Optional blocking **`recv`** / **`accept`** wait cap (ms) for bridged UDP fds and for **`accept`** on listening TCP bridge fds before **`EAGAIN`**-shaped timeout notes.
- `BARE_OS_POSIX_ACCEPT_QUEUE_MAX` — Booter — Max pending **`bareTcp.Server`** connections held before **`accept`** (default **64**, cap **1024**).
- `BARE_OS_PROTOMUX_APP_CHANNEL` — Booter / seeder — When **`1`** / **`true`**, opens a second Protomux channel **`bare-os-app-v1`** alongside **`bare-os-v1`** for namespaced app RPC (see **`bare-os-protocol`** **`PROTOCOL_APP_CHANNEL_NAME`**). - `BARE_OS_PROTOMUX_APP_CHANNEL` — Booter / seeder — When **`1`** / **`true`**, opens a second Protomux channel **`bare-os-app-v1`** alongside **`bare-os-v1`** for namespaced app RPC (see **`bare-os-protocol`** **`PROTOCOL_APP_CHANNEL_NAME`**).
- `BARE_OS_PHYS_PAGES_HINT` — Booter — Optional integer string for **`getconf _SC_PHYS_PAGES`** via **`ctx.bareOsGetconfSysconf`** (default **`524288`** when unset). - `BARE_OS_PHYS_PAGES_HINT` — Booter — Optional integer string for **`getconf _SC_PHYS_PAGES`** via **`ctx.bareOsGetconfSysconf`** (default **`524288`** when unset).
- `BARE_OS_SHELL_HEREDOC_MAX_BYTES` — Booter — When **`BARE_OS_SHELL_POSIX_MODE`** is on, caps here-document body size (default **`262144`**, max **2 MiB**). - `BARE_OS_SHELL_HEREDOC_MAX_BYTES` — Booter — When **`BARE_OS_SHELL_POSIX_MODE`** is on, caps here-document body size (default **`262144`**, max **2 MiB**).
+13
View File
@@ -17,6 +17,19 @@ Bare OS splits **hand-authored kernel code** from **vendored Holepunch runtime b
**`kernel.ext.d` ordering:** The Kahn topological sort in [`kernel/lib/init/init-main.js`](../../kernel/lib/init/init-main.js) must stay aligned with [`packages/bare-os-booter/lib/kernel-extension-resolver.js`](../../packages/bare-os-booter/lib/kernel-extension-resolver.js) (**`topologicalOrderKernelExtensions`**); CI covers this via the Brittle test **`kernel extension topological order matches guest Kahn tie-break`** in **`packages/bare-os-booter/test.js`**. Additional harness tests cover **`minCtxApiVersion`** skip paths, **`conflictsWith`** / dependency **cycles** under strict boot policy (no extension scripts run on hard failures). **`kernel.ext.d` ordering:** The Kahn topological sort in [`kernel/lib/init/init-main.js`](../../kernel/lib/init/init-main.js) must stay aligned with [`packages/bare-os-booter/lib/kernel-extension-resolver.js`](../../packages/bare-os-booter/lib/kernel-extension-resolver.js) (**`topologicalOrderKernelExtensions`**); CI covers this via the Brittle test **`kernel extension topological order matches guest Kahn tie-break`** in **`packages/bare-os-booter/test.js`**. Additional harness tests cover **`minCtxApiVersion`** skip paths, **`conflictsWith`** / dependency **cycles** under strict boot policy (no extension scripts run on hard failures).
### Strict boot / `kernel.ext.d` failure catalog (operator)
When **`BARE_OS_BOOT_POLICY_STRICT=1`** (or equivalent strict policy paths), the stock kernel may abort before running extension scripts. Common structured outcomes:
| Kind | Guest signal | Notes |
|------|----------------|-------|
| Dependency cycle | **`kernelExt.cycle`**, **`/run/bare-os/kernel-ext-resolution.json`** **`failure.kind: dependency_cycle`** | Topological sort fails; extension IDs listed in proc/trace JSON. |
| **`conflictsWith`** | **`kernelExt.conflict`** | Two loaded ids mutually exclude each other. |
| **`minCtxApiVersion`** | **`kernelExt.minCtxApiVersion`** | Drop-in skipped or strict boot fails when **`ctx.bareOsCtxApiVersion`** is below the declared floor. |
| **`denyKernelExtensionIds` / deny id** | **`kernelExt.denyId`** | Policy denies an extension **`id`** before script execution. |
| **Pear multisig gate** | **`kernelExt.multisigMissing`**, **`kernelExt.multisigInvalid`**, **`kernelExt.multisigRead`** | When multisig verification is required, **`/etc/bare-os/pear.multisig.json`** must be well-formed (**`signers`**, **`quorum`**). |
| **Extension signer pins (v2v5)** | Env **`BARE_OS_BOOT_POLICY_EXTENSION_SIGNER_PINS_V*_JSON`** | Merged from **`boot.policy.json`** when present — capability alignment for downstream verifiers; CI **`scripts/verify-boot-policy-extension-signer-pins.mjs`** guards the env mapping. |
## Governance (feature bits doc v14) ## Governance (feature bits doc v14)
New capability bits are governed by [ADR 001 — Kernel feature bit governance](../../developer-guide/adr/001-kernel-feature-bits-governance.md). **`BARE_OS_KERNEL_FEATURE_BITS_DOC`** must bump when semantics change. Bits **2830** on word 1 are assigned (see ADR). **Word 2 (`bits2`)** carries the extended seeding platform surface; always mask with **`>>> 0`**. Avoid `1 << 31` on word 1 in JS without `>>> 0` discipline. New capability bits are governed by [ADR 001 — Kernel feature bit governance](../../developer-guide/adr/001-kernel-feature-bits-governance.md). **`BARE_OS_KERNEL_FEATURE_BITS_DOC`** must bump when semantics change. Bits **2830** on word 1 are assigned (see ADR). **Word 2 (`bits2`)** carries the extended seeding platform surface; always mask with **`>>> 0`**. Avoid `1 << 31` on word 1 in JS without `>>> 0` discipline.
+2 -2
View File
@@ -1,7 +1,7 @@
{ {
"schema": 1, "schema": 1,
"profileId": "bare-os-posix-like", "profileId": "bare-os-posix-like",
"note": "Machine-readable summary; normative detail remains in handbook ch.9 and environment POSIX appendix. Profile 1.0.9 / syscalls schema 8: cooperative fcntl locks (optional F_SETLKW blocking wait; waiters wake on unlock; not full POSIX deadlock detection), SOCK_DGRAM send/sendmsg/recv/recvfrom/recvmsg + poll/select readiness on socket FD bridge, sendmsg/recvmsg partial iovec/msgHdr on bridge (ancillary CMSGS ENOTSUP), dynamic sysconf via ctx.bareOsGetconfSysconf, guestReplicationPlan via BARE_OS_REPLICATION_PLAN_JSON in /proc/bare_os/replication JSON; liveHyperdrive replication sketch schema 2 (auxiliaryDriveCount).", "note": "Machine-readable summary; normative detail remains in handbook ch.9 and environment POSIX appendix. Profile 1.0.9 / syscalls schema 8: cooperative fcntl locks (optional BARE_OS_POSIX_FCNTL_BLOCKING_WAIT: F_SETLKW FIFO waiters per path, BARE_OS_FCNTL_LOCK_WAIT_MS_MAX ETIMEDOUT; not full POSIX deadlock detection), SOCK_DGRAM send/sendmsg/recv/recvfrom/recvmsg + poll/select readiness on socket FD bridge, sendmsg/recvmsg partial iovec/msgHdr on bridge; socketMsgSurface schema 3 documents explicit ancillary rejection (ENOTSUP + ancillaryReject) on sendmsg when cmsgs/control/controllen/msgHdr.* present, recvmsg controllen 0. /bin/split uses POSIX-style multi-length suffixes (aazz then aaa…). Dynamic sysconf via ctx.bareOsGetconfSysconf, guestReplicationPlan via BARE_OS_REPLICATION_PLAN_JSON in /proc/bare_os/replication JSON; liveHyperdrive replication sketch schema 2 (auxiliaryDriveCount).",
"utilities": { "utilities": {
"tier1_bin": "high", "tier1_bin": "high",
"sed_awk_grep": "issue7_inspired_js_engines", "sed_awk_grep": "issue7_inspired_js_engines",
@@ -25,6 +25,6 @@
"syscalls_json_schema": 8, "syscalls_json_schema": 8,
"process_table_schema": 7, "process_table_schema": 7,
"paths": ["/proc/bare_os/syscalls.json", "/proc/bare_os/process_table.json"], "paths": ["/proc/bare_os/syscalls.json", "/proc/bare_os/process_table.json"],
"posix_xsh_surface": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl cooperative F_GETLK/F_SETLK/F_SETLKW + F_GETFL/F_SETFL,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown in syscalls.json posixXsh.namesCsv; default socket ENOSYS-shaped; BARE_OS_POSIX_SOCKET_FD_BRIDGE SOCK_STREAM connect via bareTcp, SOCK_DGRAM connect+send+sendmsg+recv+recvfrom+recvmsg via bareDgram with BARE_OS_POSIX_DGRAM_RECVQ_MAX / BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX; poll/select mark UDP bridge fds readable when queue non-empty; ctx.bareOsSyscall readv/writev on POSIX_FD_SIM pipes; ctx.bareOsPosixPoll; socketMsgSurface schema 2 documents partial sendmsg/recvmsg on bridge (ancillary ENOTSUP)" "posix_xsh_surface": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl cooperative F_GETLK/F_SETLK/F_SETLKW + F_GETFL/F_SETFL,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown in syscalls.json posixXsh.namesCsv; default socket ENOSYS-shaped; BARE_OS_POSIX_SOCKET_FD_BRIDGE SOCK_STREAM connect via bareTcp; passive SOCK_STREAM bind+listen+accept via bareTcp.Server; accepted stream fds use send/recv with bounded tcpRecvQueue; SOCK_DGRAM connect+send+sendmsg+recv+recvfrom+recvmsg via bareDgram with BARE_OS_POSIX_DGRAM_RECVQ_MAX / BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX; BARE_OS_POSIX_ACCEPT_QUEUE_MAX; poll/select mark UDP bridge fds readable when queue non-empty, TCP accepted fds when tcpRecvQueue non-empty, listening fds when accept queue non-empty; ctx.bareOsSyscall readv/writev on POSIX_FD_SIM pipes; ctx.bareOsPosixPoll; socketMsgSurface schema 3 documents partial sendmsg/recvmsg on bridge + ancillaryControl rejection contract"
} }
} }
+2 -2
View File
@@ -10,7 +10,7 @@ Normative narrative: [`docs/architecture/POSIX_DECLARED_PROFILE.md`](../architec
| --- | --- | --- | | --- | --- | --- |
| Profile | profileId | bare-os-posix-like | | Profile | profileId | bare-os-posix-like |
| Profile | schema | 1 | | Profile | schema | 1 |
| Profile | note | Machine-readable summary; normative detail remains in handbook ch.9 and environment POSIX appendix. Profile 1.0.9 / syscalls schema 8: cooperative fcntl locks (optional F_SETLKW blocking wait; waiters wake on unlock; not full POSIX deadlock detection), SOCK_DGRAM send/sendmsg/recv/recvfrom/recvmsg + poll/select readiness on socket FD bridge, sendmsg/recvmsg partial iovec/msgHdr on bridge (ancillary CMSGS ENOTSUP), dynamic sysconf via ctx.bareOsGetconfSysconf, guestReplicationPlan via BARE_OS_REPLICATION_PLAN_JSON in /proc/bare_os/replication JSON; liveHyperdrive replication sketch schema 2 (auxiliaryDriveCount). | | Profile | note | Machine-readable summary; normative detail remains in handbook ch.9 and environment POSIX appendix. Profile 1.0.9 / syscalls schema 8: cooperative fcntl locks (optional BARE_OS_POSIX_FCNTL_BLOCKING_WAIT: F_SETLKW FIFO waiters per path, BARE_OS_FCNTL_LOCK_WAIT_MS_MAX ETIMEDOUT; not full POSIX deadlock detection), SOCK_DGRAM send/sendmsg/recv/recvfrom/recvmsg + poll/select readiness on socket FD bridge, sendmsg/recvmsg partial iovec/msgHdr on bridge; socketMsgSurface schema 3 documents explicit ancillary rejection (ENOTSUP + ancillaryReject) on sendmsg when cmsgs/control/controllen/msgHdr.* present, recvmsg controllen 0. /bin/split uses POSIX-style multi-length suffixes (aazz then aaa…). Dynamic sysconf via ctx.bareOsGetconfSysconf, guestReplicationPlan via BARE_OS_REPLICATION_PLAN_JSON in /proc/bare_os/replication JSON; liveHyperdrive replication sketch schema 2 (auxiliaryDriveCount). |
| Utilities | tier1_bin | high | | Utilities | tier1_bin | high |
| Utilities | sed_awk_grep | issue7_inspired_js_engines | | Utilities | sed_awk_grep | issue7_inspired_js_engines |
| Utilities | coreutils | see packages/bare-os-coreutils/src | | Utilities | coreutils | see packages/bare-os-coreutils/src |
@@ -27,4 +27,4 @@ Normative narrative: [`docs/architecture/POSIX_DECLARED_PROFILE.md`](../architec
| synthetic /proc | syscalls_json_schema | 8 | | synthetic /proc | syscalls_json_schema | 8 |
| synthetic /proc | process_table_schema | 7 | | synthetic /proc | process_table_schema | 7 |
| synthetic /proc | paths | /proc/bare_os/syscalls.json, /proc/bare_os/process_table.json | | synthetic /proc | paths | /proc/bare_os/syscalls.json, /proc/bare_os/process_table.json |
| synthetic /proc | posix_xsh_surface | open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl cooperative F_GETLK/F_SETLK/F_SETLKW + F_GETFL/F_SETFL,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown in syscalls.json posixXsh.namesCsv; default socket ENOSYS-shaped; BARE_OS_POSIX_SOCKET_FD_BRIDGE SOCK_STREAM connect via bareTcp, SOCK_DGRAM connect+send+sendmsg+recv+recvfrom+recvmsg via bareDgram with BARE_OS_POSIX_DGRAM_RECVQ_MAX / BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX; poll/select mark UDP bridge fds readable when queue non-empty; ctx.bareOsSyscall readv/writev on POSIX_FD_SIM pipes; ctx.bareOsPosixPoll; socketMsgSurface schema 2 documents partial sendmsg/recvmsg on bridge (ancillary ENOTSUP) | | synthetic /proc | posix_xsh_surface | open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl cooperative F_GETLK/F_SETLK/F_SETLKW + F_GETFL/F_SETFL,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown in syscalls.json posixXsh.namesCsv; default socket ENOSYS-shaped; BARE_OS_POSIX_SOCKET_FD_BRIDGE SOCK_STREAM connect via bareTcp; passive SOCK_STREAM bind+listen+accept via bareTcp.Server; accepted stream fds use send/recv with bounded tcpRecvQueue; SOCK_DGRAM connect+send+sendmsg+recv+recvfrom+recvmsg via bareDgram with BARE_OS_POSIX_DGRAM_RECVQ_MAX / BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX; BARE_OS_POSIX_ACCEPT_QUEUE_MAX; poll/select mark UDP bridge fds readable when queue non-empty, TCP accepted fds when tcpRecvQueue non-empty, listening fds when accept queue non-empty; ctx.bareOsSyscall readv/writev on POSIX_FD_SIM pipes; ctx.bareOsPosixPoll; socketMsgSurface schema 3 documents partial sendmsg/recvmsg on bridge + ancillaryControl rejection contract |
@@ -0,0 +1,25 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://bare-os.local/schemas/bare-os-hrpc-allowlist.schema.json",
"title": "BARE_OS_HRPC_ALLOWLIST_JSON",
"description": "Optional allowlist for stock ctx.bareOsHrpcRequest. Parsed by packages/bare-os-booter/lib/bare-os-hrpc-allowlist.js. An empty allow set (empty array or all-falsy object) does not restrict routes.",
"oneOf": [
{
"type": "array",
"items": {
"type": "string",
"pattern": "^[a-zA-Z0-9._-]{1,64}\\.[a-zA-Z0-9._-]{1,96}$|^[a-zA-Z0-9._*.-]{1,64}$",
"description": "service.method or wildcard token such as * or kernel.*"
},
"maxItems": 512
},
{
"type": "object",
"additionalProperties": { "type": "boolean" },
"propertyNames": {
"pattern": "^[a-zA-Z0-9._*.-]{1,160}$"
},
"maxProperties": 512
}
]
}
+13 -1
View File
@@ -57,9 +57,21 @@
}, },
"socketMsgSurface": { "socketMsgSurface": {
"type": "object", "type": "object",
"description": "sendmsg/recvmsg metadata (defaults ENOTSUP; bridge uses recv/recvfrom buffers only)", "description": "sendmsg/recvmsg metadata (defaults ENOTSUP; bridge uses recv/recvfrom buffers only); schema 3 adds ancillaryControl rejection contract",
"properties": { "properties": {
"schema": { "type": "integer" }, "schema": { "type": "integer" },
"ancillaryControl": {
"type": "object",
"properties": {
"supported": { "type": "boolean" },
"errno": { "type": "string" },
"rejectKeys": {
"type": "array",
"items": { "type": "string" }
},
"note": { "type": "string" }
}
},
"sendmsg": { "type": "object" }, "sendmsg": { "type": "object" },
"recvmsg": { "type": "object" } "recvmsg": { "type": "object" }
} }
+2
View File
@@ -16,6 +16,8 @@ This chapter covers **who the session is** (guest vs unlocked), **where keys liv
**Pairing hints (operators):** when the host sets **`BARE_OS_AUTOPASS_INVITE_URL`**, the guest exposes a JSON hint at **`/proc/bare_os/hdms_hints.json`**. The guest does **not** open network URLs automatically; hosts or operators consume the hint out-of-band. **`/proc/bare_os/hdms_health.json`** (and flat alias) summarizes **non-secret** mount/registry metadata (counts, labels) for dashboards—no key material. **Pairing hints (operators):** when the host sets **`BARE_OS_AUTOPASS_INVITE_URL`**, the guest exposes a JSON hint at **`/proc/bare_os/hdms_hints.json`**. The guest does **not** open network URLs automatically; hosts or operators consume the hint out-of-band. **`/proc/bare_os/hdms_health.json`** (and flat alias) summarizes **non-secret** mount/registry metadata (counts, labels) for dashboards—no key material.
**Unlock errors (automation):** when **`unlockIdentity`** in [`identity-session.js`](../packages/bare-os-booter/lib/identity-session.js) throws, stable **`Error.code`** values include **`BARE_OS_IDENTITY_NO_ACCOUNT`** (no **`/.bare/account`** blob) and **`BARE_OS_IDENTITY_PASSPHRASE_REJECTED`** (decrypt/parse failure; **`error.cause`** carries the underlying error when present). Human-readable messages remain for interactive **`login`**.
Cron note: **`crontab`** install/remove requires **unlocked** identity so arbitrary guests cannot overwrite **`~/.crontab`**. Cron note: **`crontab`** install/remove requires **unlocked** identity so arbitrary guests cannot overwrite **`~/.crontab`**.
--- ---
+12
View File
@@ -12,6 +12,7 @@ This chapter is the **operators desk**: how to install, test, run Pear apps,
- [Continuous integration](#continuous-integration-github-actions) - [Continuous integration](#continuous-integration-github-actions)
- [`pretest`](#pretest-what-runs-before-npm-test) - [`pretest`](#pretest-what-runs-before-npm-test)
- [Holepunch catalog and Bare manifest](#holepunch-catalog-and-bare-manifest-maintainers) - [Holepunch catalog and Bare manifest](#holepunch-catalog-and-bare-manifest-maintainers)
- [Warm read cache (operators)](#warm-read-cache-operators)
- [Release checklist](#release-checklist) - [Release checklist](#release-checklist)
- [Install and test](#install-and-test) - [Install and test](#install-and-test)
- [Running seeder and booter (Node)](#running-seeder-and-booter-node) - [Running seeder and booter (Node)](#running-seeder-and-booter-node)
@@ -89,6 +90,17 @@ Each **`npm run build -w bare-os-bare-libs`** run writes **`kernel/lib/bare/mani
Use provenance to audit which commit produced an images Holepunch IIFEs and to compare bundle tiers across environments. Use provenance to audit which commit produced an images Holepunch IIFEs and to compare bundle tiers across environments.
### Warm read cache (operators)
When **`BARE_OS_VFS_BIN_CACHE`** and/or **`BARE_OS_VFS_LIB_BARE_CACHE`** are on, the booter serves hot **`/bin`** and **`/lib/bare`** reads from an LRU. After **live replication**, **OTA-style `/bin` or `/lib/bare` writes**, or **`kernel.ext.d` hot reload** that changes bundles, stale bytes are a real risk.
1. Prefer **`ctx.bareOsVfsBatchWrite`** for batch **`put`** operations — it clears warm entries when paths touch **`bin/`**, **`lib/bare/`**, **`boot/init.js`**, or **`lib/init/`**, and uses **selective** **`vfs.bareOsEvictLibBareBundlesFromManifest`** when only **`lib/bare/bare-module-manifest.json`** changes.
2. Call **`ctx.bareOsInvalidateWarmReadCaches('reason')`** (or **`vfs.bareOsClearWarmReadCaches()`**) after host-driven replication or policy changes that bypass the batch writer.
3. For manifest-only updates, use **`ctx.bareOsInvalidateWarmReadCachesFromBareManifestJson(buf)`** to evict **`bundles/<ctxKey>.js`** rows without flushing unrelated cache entries.
4. Optional **`BARE_OS_VFS_WARM_CACHE_INVALIDATE_ON_APPEND`** registers Hypercore **append** listeners so replication can clear caches automatically (higher churn on busy drives).
Tests in **`packages/bare-os-booter/test.js`** cover hit/miss, full clear, manifest-selective eviction, and hrpc allowlist helpers adjacent to the VFS suite.
### Pear bundle and pack pipeline (OS images) ### Pear bundle and pack pipeline (OS images)
For Pear-shaped releases, align **`pear-bundle`** / **`pear-pack`** with the same **`kernel/`** tree the seeder stages: run **`npm run build -w bare-os-coreutils`** and **`npm run build -w bare-os-bare-libs`**, verify **`scripts/verify-kernel-seeder-parity.mjs`**, then point Pear tooling at **`packages/bare-os-seeder`** or the published Hyperdrive key. Keep **`pear-runtime`** and **`bare-os-protocol`** versions coupled per [compatibility-matrix.md](../docs/reference/compatibility-matrix.md). For Pear-shaped releases, align **`pear-bundle`** / **`pear-pack`** with the same **`kernel/`** tree the seeder stages: run **`npm run build -w bare-os-coreutils`** and **`npm run build -w bare-os-bare-libs`**, verify **`scripts/verify-kernel-seeder-parity.mjs`**, then point Pear tooling at **`packages/bare-os-seeder`** or the published Hyperdrive key. Keep **`pear-runtime`** and **`bare-os-protocol`** versions coupled per [compatibility-matrix.md](../docs/reference/compatibility-matrix.md).
+6 -6
View File
@@ -12,7 +12,7 @@ If you come from Linux or macOS, Bare OS **feels** like a small Unix: **`ls`**,
**Declared profile (single spec):** [POSIX_DECLARED_PROFILE.md](../docs/architecture/POSIX_DECLARED_PROFILE.md) — contract for XCU/XSH-like behavior, proc stand-ins for “syscalls,” and explicit non-goals. **Declared profile (single spec):** [POSIX_DECLARED_PROFILE.md](../docs/architecture/POSIX_DECLARED_PROFILE.md) — contract for XCU/XSH-like behavior, proc stand-ins for “syscalls,” and explicit non-goals.
**Declared profile (constants):** the protocol package publishes **`BARE_OS_POSIX_PROFILE_VERSION`** / **`BARE_OS_POSIX_PROFILE_ID`** (`bare-os-posix-like`), surfaced on **`/proc/bare_os_features`** and in **`/proc/bare_os/syscalls.json`** (schema **8** for that file — **`fdModel`** / **`signalModel`** plus **`opsDetail`** / **`posixXsh`** (schema **2**) / **`socketMsgSurface`** (schema **2**) / **`errnoHints`**, including cooperative **`fcntl`** advisory locks with optional **`F_SETLKW`** blocking wait (**`BARE_OS_POSIX_FCNTL_BLOCKING_WAIT`**) and optional socket-bridge datagram **`send`/`sendmsg`/`recv`/`recvfrom`/`recvmsg`** with bounded queues (**ancillary CMSGS remain ENOTSUP**); **`/proc/bare_os/index.json`** uses schema **8**). **`getconf BARE_OS_POSIX_XSH_OPS`** lists the XSH names; **`getconf BARE_OS_SYSCALL_OPS`** lists ctx op names only. Cold-boot wall time vs **`BARE_OS_BOOT_BUDGET_MS_COLD`** is also written to **`/run/bare-os/boot-perf.json`** when the VFS supports it. **`metrics_live`** includes **`initdReadiness`** (schema **2**) and paths such as **`utilitiesIndexPath`** → **`/etc/bare-os/posix_utilities.json`** when present. **Declared profile (constants):** the protocol package publishes **`BARE_OS_POSIX_PROFILE_VERSION`** / **`BARE_OS_POSIX_PROFILE_ID`** (`bare-os-posix-like`), surfaced on **`/proc/bare_os_features`** and in **`/proc/bare_os/syscalls.json`** (schema **8** for that file — **`fdModel`** / **`signalModel`** plus **`opsDetail`** / **`posixXsh`** (schema **2**) / **`socketMsgSurface`** (schema **3**: non-empty ancillary on **`sendmsg`** → **`ENOTSUP`** + **`ancillaryReject`**; **`recvmsg`** **`controllen: 0`**) / **`errnoHints`**, including cooperative **`fcntl`** advisory locks with optional **`F_SETLKW`** blocking wait (**`BARE_OS_POSIX_FCNTL_BLOCKING_WAIT`**) and optional socket-bridge datagram **`send`/`sendmsg`/`recv`/`recvfrom`/`recvmsg`** with bounded queues; **`/proc/bare_os/index.json`** uses schema **8**). **`getconf BARE_OS_POSIX_XSH_OPS`** lists the XSH names; **`getconf BARE_OS_SYSCALL_OPS`** lists ctx op names only. Cold-boot wall time vs **`BARE_OS_BOOT_BUDGET_MS_COLD`** is also written to **`/run/bare-os/boot-perf.json`** when the VFS supports it. **`metrics_live`** includes **`initdReadiness`** (schema **2**) and paths such as **`utilitiesIndexPath`** → **`/etc/bare-os/posix_utilities.json`** when present.
--- ---
@@ -42,7 +42,7 @@ We borrow **names and muscle memory** from POSIX because that makes scripts port
## 1. Executive summary: what is _not_ POSIX here ## 1. Executive summary: what is _not_ POSIX here
- **Full POSIX `sh` grammar** — Bare uses a **line-at-a-time** shell: builtins plus **`/bin`**; lists with **`;`** (outside compound statements), **`&&`**, and **`|`** pipelines; bounded **`if`** … **`fi`**; bounded **`while`** / **`for`** (iteration cap **`BARE_OS_SHELL_LOOP_MAX`**, default **10000**); optional **`break`** / **`continue`** when **`BARE_OS_SHELL_LOOP_CONTROL=1`**; bounded **`case`** … **`esac`** (**`BARE_OS_SHELL_CASE_MAX_BRANCHES`**, default **32**). Optional bounded **`$(…)`** when **`BARE_OS_SHELL_CMDSUBST=1`** (see §3). With **`BARE_OS_SHELL_POSIX_MODE=1`**, **subshell-free grouped lists** **`( compound-list )`** run as a single statement (same session context). There are **no forked subshells** and no full **`sh`** grammar. - **Full POSIX `sh` grammar** — Bare uses a **line-at-a-time** shell: builtins plus **`/bin`**; lists with **`;`** (outside compound statements), **`&&`**, and **`|`** pipelines; bounded **`if`** … **`fi`**; bounded **`while`** / **`for`** (iteration cap **`BARE_OS_SHELL_LOOP_MAX`**, default **10000**); optional **`break`** / **`continue`** when **`BARE_OS_SHELL_LOOP_CONTROL=1`**; bounded **`case`** … **`esac`** (**`BARE_OS_SHELL_CASE_MAX_BRANCHES`**, default **32**). Optional bounded **`$(…)`** when **`BARE_OS_SHELL_CMDSUBST=1`** (see §3). With **`BARE_OS_SHELL_POSIX_MODE=1`**, **subshell-free grouped lists** **`( compound-list )`** run as a single statement (same session context). There are **no forked subshells** and no full **`sh`** grammar.
- **Processes, `fork`, pipes as OS primitives** — Pipelines are **simulated** by capturing **`console.log`** (and merged **`console.error`** when **`2>&1`** is used) into the next command. With **`BARE_OS_POSIX_FD_SIM=1`**, extensions may also use **`ctx.bareOsPosixFdSimPipe`** / **`bareOsPosixFdSimRead`** / **`bareOsPosixFdSimWrite`** for bounded in-memory pipe pairs surfaced as logical FDs in **`/proc/self/fd`** (not full kernel pipes). Logical FDs support **`ctx.bareOsSyscall('fcntl', { fd, cmd: 'F_GETFL' | 'F_SETFL', arg })`** (Linux-shaped **`O_APPEND`** **`0x400`**, **`O_NONBLOCK`** **`0x800`**), cooperative **`F_GETLK` / `F_SETLK` / `F_SETLKW`** on absolute paths (or fd→path), and readiness via **`ctx.bareOsPosixPoll`** / **`ctx.bareOsSyscall('posixPoll', { fds, timeoutMs })`** (see **`/proc/bare_os/syscalls.json`**). Cooperative locks are **not** kernel wait queues: **`F_SETLKW`** may surface an **`EINTR`-shaped note** when the blocking wait budget elapses or a stale-owner grace window passes — there is no host deadlock detector. With **`BARE_OS_POSIX_SOCKET_FD_BRIDGE=1`**, **`socket`** + **`connect`** may use **`ctx.bare.bareTcp`** for **`SOCK_STREAM`** and **`ctx.bare.bareDgram`** for **`SOCK_DGRAM`** when merged; bridged UDP supports **`send`**, **`recv`**, and **`recvfrom`** with **`BARE_OS_POSIX_DGRAM_RECVQ_MAX`** / **`BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX`**, and **`poll`/`select`** treat the fd readable when the queue is non-empty. - **Processes, `fork`, pipes as OS primitives** — Pipelines are **simulated** by capturing **`console.log`** (and merged **`console.error`** when **`2>&1`** is used) into the next command. With **`BARE_OS_POSIX_FD_SIM=1`**, extensions may also use **`ctx.bareOsPosixFdSimPipe`** / **`bareOsPosixFdSimRead`** / **`bareOsPosixFdSimWrite`** for bounded in-memory pipe pairs surfaced as logical FDs in **`/proc/self/fd`** (not full kernel pipes). Logical FDs support **`ctx.bareOsSyscall('fcntl', { fd, cmd: 'F_GETFL' | 'F_SETFL', arg })`** (Linux-shaped **`O_APPEND`** **`0x400`**, **`O_NONBLOCK`** **`0x800`**), cooperative **`F_GETLK` / `F_SETLK` / `F_SETLKW`** on absolute paths (or fd→path), and readiness via **`ctx.bareOsPosixPoll`** / **`ctx.bareOsSyscall('posixPoll', { fds, timeoutMs })`** (see **`/proc/bare_os/syscalls.json`**). Cooperative locks are **not** kernel wait queues: **`F_SETLKW`** may surface an **`EINTR`-shaped note** when the blocking wait budget elapses or a stale-owner grace window passes — there is no host deadlock detector. With **`BARE_OS_POSIX_SOCKET_FD_BRIDGE=1`**, **`socket`** + **`connect`** may use **`ctx.bare.bareTcp`** for **`SOCK_STREAM`** and **`ctx.bare.bareDgram`** for **`SOCK_DGRAM`** when merged; passive **`SOCK_STREAM`** uses **`bind`**, **`listen`**, **`accept`** (**`bareTcp.Server`**) with **`BARE_OS_POSIX_ACCEPT_QUEUE_MAX`**; accepted stream fds support **`send`/`recv`** with a bounded segment queue (same cap family as **`BARE_OS_POSIX_DGRAM_RECVQ_MAX`**). Bridged UDP supports **`send`**, **`recv`**, and **`recvfrom`** with **`BARE_OS_POSIX_DGRAM_RECVQ_MAX`** / **`BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX`**, and **`poll`/`select`** treat the fd readable when the datagram queue is non-empty (listening and TCP-accepted fds use their respective queues).
- **`chown` / `chgrp` / real UIDs across users** — **Single-session** identity; metadata carries **uid/gid** for display and checks, not a multi-user kernel. - **`chown` / `chgrp` / real UIDs across users** — **Single-session** identity; metadata carries **uid/gid** for display and checks, not a multi-user kernel.
- **FIFOs, `mknod`, real devices** — No kernel FIFOs or **`mknod`**; **`mkfifo`** creates **in-memory** channels under **`/run/bare-os/ipc/<name>`** (see **`bare-os-ipc.js`**). Optional **`BARE_OS_IPC_MAX_CHANNELS`** caps distinct channel keys; **`metrics_live.ipcTelemetry`** mirrors FIFO depth, fan-out counts, and quota counters. - **FIFOs, `mknod`, real devices** — No kernel FIFOs or **`mknod`**; **`mkfifo`** creates **in-memory** channels under **`/run/bare-os/ipc/<name>`** (see **`bare-os-ipc.js`**). Optional **`BARE_OS_IPC_MAX_CHANNELS`** caps distinct channel keys; **`metrics_live.ipcTelemetry`** mirrors FIFO depth, fan-out counts, and quota counters.
- **Full POSIX/GNU `xargs`** — Bounded implementation: **`ctx.runBinCommand`** only; **`-0`**, **`-n`** (and **`-nN`**), optional **`-P`** parallelism with effective cap **`min(requested, BARE_OS_XARGS_MAX_PROCS, 32)`** (default **8** when env unset; sequential when **`0`**); stdin, token, and invocation caps (see **`src/xargs.js`**). - **Full POSIX/GNU `xargs`** — Bounded implementation: **`ctx.runBinCommand`** only; **`-0`**, **`-n`** (and **`-nN`**), optional **`-P`** parallelism with effective cap **`min(requested, BARE_OS_XARGS_MAX_PROCS, 32)`** (default **8** when env unset; sequential when **`0`**); stdin, token, and invocation caps (see **`src/xargs.js`**).
@@ -72,7 +72,7 @@ Hyperdrive does not always behave like a POSIX directory tree. Empty directories
### 2.3 Pseudo **`/proc`**, **`/sys`**, **`/run`**, **`/dev`**, and session **`/tmp`** ### 2.3 Pseudo **`/proc`**, **`/sys`**, **`/run`**, **`/dev`**, and session **`/tmp`**
- **`/proc`**, **`/sys`**, **`/run`**, **`/dev`** — read-only synthetic trees except **`/dev/null`** and **`/dev/zero`** accept writes that are discarded, and **`/dev/shm/<name>`** accepts **`writeFile`** / **`readFile`** / **`unlink`** for **in-memory** named segments (see [POSIX declared profile](../docs/architecture/POSIX_DECLARED_PROFILE.md)). Other pseudo **`writeFile`** / **`unlink`** / **`chmod`** paths fail as documented there. Linux-shaped **synthetic** files include **`/proc/cpuinfo`**, **`/proc/meminfo`**, **`/proc/loadavg`**, **`/proc/net/dev`**, **`/proc/diskstats`**, and **data-backed** **`/proc/self/cgroups`**, **`/proc/net/tcp`**, **`/proc/net/udp`** (session / swarm / quota hints; stable columns where practical). **`/proc/bare_os/`** (stable aliases + **`index.json`** schema **8**, listing Pear/Bare operator JSON from Capability words 611 such as **`pear_stage_pointer.json`**, **`bare_module_resolution.json`**, **`pear_doctor_state.json`**, **`bare_boot_phase_map.json`**, …, plus **`syscalls.json`** (schema **5**; stock booter **caches** JSON until warm read-cache invalidation), **`process_table.json`** (**schema 5**: PGID/SID-style fields, **`parentName`**, **`signalRouting`**, initd binding), **`metrics.prom`**, **`protomux.json`** (schema **2** RPC pool / backpressure hints), **`/proc/bare_os_quotas`**, **`/proc/bare_os_resources`**, **`/proc/bare_os_features`**, **`/proc/bare_os_session_stats`**, **`/proc/bare_os_swarm`**, **`/proc/bare_os_replication`**, **`/proc/bare_os_manifest_hints`**, **`/proc/bare_os_peer_health`**, **`/proc/bare_os_staging_slot`**, **`/proc/bare_os_snapshot_hints`**, **`/proc/bare_os_provenance`**, **`/proc/bare_os_pear_ipc_registry`**, **`/proc/bare_os_initd_dag`**, **`/proc/bare_os_initd_graph`**, **`/proc/bare_os_pear_trust`**, **`/proc/bare_os_rlimits`**, **`/proc/bare_os_hdms_health`**, **`/proc/bare_os_metrics_live`** (and **`/proc/bare_os/metrics_live.json`**), **`/proc/bare_os/metrics.prom`** (OpenMetrics text for kernel counters), **`/proc/bare_os_extensions.json`**, **`/proc/bare_os_hdms_hints.json`**, **`/proc/bare_os_capabilities`** (and **`/proc/bare_os_capabilities.json`**), **`/proc/bare_os_bootstrap`**, **`/proc/bare_os_union`**, **`/proc/bare_os_seed_handshake`**, **`/proc/bare_os_virtual_registry`**, **`/proc/self/cgroups`**, **`/proc/self/exe`**, **`/proc/self/fd/0``2`**, **`/sys/class/net/lo`**, **`/sys/devices/virtual`**, **`/sys/fs/bare_os/build_id`**, **`/run/bare-os/virtual/*`**, **`/run/bare-os/unit-journal/*.ndjson`**, **`/run/bare-os/kernel-ext-reload.ndjson`** (append-only **`kernelExtReloadSchemaVersion`** lines when **`BARE_OS_KERNEL_EXT_D_HOT_RELOAD`** and **`ctx.bareOsReloadKernelExtDropinsSafe()`** run), and **`/dev/urandom`** (each **`readFile`** of urandom returns a **bounded** buffer; **not** suitable for cryptography unless **`BARE_OS_URANDOM_CRYPTO`** is left at default). Optional union write denials use **`BARE_OS_VFS_UNION_WRITE_DENY`** (see [kernel extensions](../docs/reference/kernel-extensions.md)). With **`BARE_OS_VFS_WATCH_PSEUDO=1`**, **`vfs.watch`** may poll coalesced **`metrics_live`** and **`metrics.prom`**. With **`BARE_OS_VFS_WATCH_SWARM=1`**, **`vfs.watch`** may poll coalesced **`swarm`** / **`replication`** pseudo files. Use **`ctx.bareOsReadProcMetricsLive()`** for the same JSON as **`metrics_live`** without a VFS read. **`/bin/env`** supports **`-S`** / **`--env-file`** when **`BARE_OS_ENV_DASH_S=1`**. Shell **`${…}`** v2 (**`##`**, **`%%`**, **`:=`**, basename **`*/`**) requires **`BARE_OS_SHELL_PARAM_EXPANSION_V2=1`** with param expansion enabled. V3 adds **`:?`** / **`:+`** when **`BARE_OS_SHELL_PARAM_EXPANSION_V3=1`**. Gated **`local`** / read-only **`declare -r`** use **`BARE_OS_SHELL_LOCAL_DECLARE=1`**. - **`/proc`**, **`/sys`**, **`/run`**, **`/dev`** — read-only synthetic trees except **`/dev/null`** and **`/dev/zero`** accept writes that are discarded, and **`/dev/shm/<name>`** accepts **`writeFile`** / **`readFile`** / **`unlink`** for **in-memory** named segments (see [POSIX declared profile](../docs/architecture/POSIX_DECLARED_PROFILE.md)). Other pseudo **`writeFile`** / **`unlink`** / **`chmod`** paths fail as documented there. Linux-shaped **synthetic** files include **`/proc/cpuinfo`**, **`/proc/meminfo`**, **`/proc/loadavg`**, **`/proc/net/dev`**, **`/proc/diskstats`**, and **data-backed** **`/proc/self/cgroups`**, **`/proc/net/tcp`**, **`/proc/net/udp`** (session / swarm / quota hints; stable columns where practical). **`/proc/bare_os/`** (stable aliases + **`index.json`** schema **8**, listing Pear/Bare operator JSON from Capability words 611 such as **`pear_stage_pointer.json`**, **`bare_module_resolution.json`**, **`pear_doctor_state.json`**, **`bare_boot_phase_map.json`**, …, plus **`syscalls.json`** (schema **8**; stock booter **caches** JSON until warm read-cache invalidation), **`process_table.json`** (**schema 7**: PGID/SID-style fields, **`parentName`**, **`signalRouting`**, initd binding), **`metrics.prom`**, **`protomux.json`** (schema **2** RPC pool / backpressure hints), **`/proc/bare_os_quotas`**, **`/proc/bare_os_resources`**, **`/proc/bare_os_features`**, **`/proc/bare_os_session_stats`**, **`/proc/bare_os_swarm`**, **`/proc/bare_os_replication`**, **`/proc/bare_os_manifest_hints`**, **`/proc/bare_os_peer_health`**, **`/proc/bare_os_staging_slot`**, **`/proc/bare_os_snapshot_hints`**, **`/proc/bare_os_provenance`**, **`/proc/bare_os_pear_ipc_registry`**, **`/proc/bare_os_initd_dag`**, **`/proc/bare_os_initd_graph`**, **`/proc/bare_os_pear_trust`**, **`/proc/bare_os_rlimits`**, **`/proc/bare_os_hdms_health`**, **`/proc/bare_os_metrics_live`** (and **`/proc/bare_os/metrics_live.json`**), **`/proc/bare_os/metrics.prom`** (OpenMetrics text for kernel counters), **`/proc/bare_os_extensions.json`**, **`/proc/bare_os_hdms_hints.json`**, **`/proc/bare_os_capabilities`** (and **`/proc/bare_os_capabilities.json`**), **`/proc/bare_os_bootstrap`**, **`/proc/bare_os_union`**, **`/proc/bare_os_seed_handshake`**, **`/proc/bare_os_virtual_registry`**, **`/proc/self/cgroups`**, **`/proc/self/exe`**, **`/proc/self/fd/0``2`**, **`/sys/class/net/lo`**, **`/sys/devices/virtual`**, **`/sys/fs/bare_os/build_id`**, **`/run/bare-os/virtual/*`**, **`/run/bare-os/unit-journal/*.ndjson`**, **`/run/bare-os/kernel-ext-reload.ndjson`** (append-only **`kernelExtReloadSchemaVersion`** lines when **`BARE_OS_KERNEL_EXT_D_HOT_RELOAD`** and **`ctx.bareOsReloadKernelExtDropinsSafe()`** run), and **`/dev/urandom`** (each **`readFile`** of urandom returns a **bounded** buffer; **not** suitable for cryptography unless **`BARE_OS_URANDOM_CRYPTO`** is left at default). Optional union write denials use **`BARE_OS_VFS_UNION_WRITE_DENY`** (see [kernel extensions](../docs/reference/kernel-extensions.md)). With **`BARE_OS_VFS_WATCH_PSEUDO=1`**, **`vfs.watch`** may poll coalesced **`metrics_live`** and **`metrics.prom`**. With **`BARE_OS_VFS_WATCH_SWARM=1`**, **`vfs.watch`** may poll coalesced **`swarm`** / **`replication`** pseudo files. Use **`ctx.bareOsReadProcMetricsLive()`** for the same JSON as **`metrics_live`** without a VFS read. **`/bin/env`** supports **`-S`** / **`--env-file`** when **`BARE_OS_ENV_DASH_S=1`**. Shell **`${…}`** v2 (**`##`**, **`%%`**, **`:=`**, basename **`*/`**) requires **`BARE_OS_SHELL_PARAM_EXPANSION_V2=1`** with param expansion enabled. V3 adds **`:?`** / **`:+`** when **`BARE_OS_SHELL_PARAM_EXPANSION_V3=1`**. Gated **`local`** / read-only **`declare -r`** use **`BARE_OS_SHELL_LOCAL_DECLARE=1`**.
- **`/tmp`** — writable on the **personal** drive under **`/.bare-os/tmp/<HOME-basename>/…`**, isolated like **`$HOME`** and **`/var/log`**. - **`/tmp`** — writable on the **personal** drive under **`/.bare-os/tmp/<HOME-basename>/…`**, isolated like **`$HOME`** and **`/var/log`**.
### 2.4 `chmod` (octal and symbolic) ### 2.4 `chmod` (octal and symbolic)
@@ -95,7 +95,7 @@ With **`BARE_OS_VFS_BIN_CACHE=1`**, the booter keeps a bounded LRU of system-dri
### 2.6 Copy and move ### 2.6 Copy and move
- **`cp`** — **`-R`/`-r`** recursive copy; follows the same marker convention (skips copying **`.bareos_empty`** as a separate “file” where appropriate). - **`cp`** — **`-R`/`-r`** recursive copy; follows the same marker convention (skips copying **`.bareos_empty`** as a separate “file” where appropriate).
- **`mv`** — Hyperdrive has no atomic **`rename`**; the general case is copy-tree + **`vfs.rm`** on the source. A **single regular file** to a non-directory destination uses **`readFile``writeFile``unlink`** on the source (same semantics, slightly less overhead than recursive **`rm`**). - **`mv`** — Hyperdrive has no atomic **`rename`**; the general case is copy-tree + **`vfs.rm`** on the source. A **single regular file** to a non-directory destination uses a **two-phase write** (stage as **`.bare-os-mv-tmp.*`** in the **resolved destination directory**, write destination, remove stage, **`unlink`** source) so a failed destination write does not remove the source (see [POSIX declared profile](../docs/architecture/POSIX_DECLARED_PROFILE.md)).
--- ---
@@ -174,7 +174,7 @@ Beyond **`alias`**, **`unalias`**, **`cd`**, **`export`**, **`login`**, **`logou
## 5. `/bin` utilities (catalog) ## 5. `/bin` utilities (catalog)
Sources: **`packages/bare-os-coreutils/src/<name>.js`**. **Authoritative sorted list:** **`packages/bare-os-coreutils/lib/commands.mjs`** (**`COREUTILS_COMMANDS`**), consumed by **`build.mjs`**. Sources: **`packages/bare-os-coreutils/src/<name>.js`**. **Authoritative sorted list:** **`packages/bare-os-coreutils/lib/commands.mjs`** (**`COREUTILS_COMMANDS`**), consumed by **`build.mjs`**. **`man(1)`** pages are kept in lockstep with that list: CI runs **`scripts/verify-man-coverage.mjs`** (every Tier-1 **`/bin`** name has merged JSON under **`kernel/share/man/`** after **`npm run build -w bare-os-coreutils`**).
### 5.1 Filesystem and links ### 5.1 Filesystem and links
@@ -222,7 +222,7 @@ When **`BARE_OS_VFS_UNION_PREFIXES`** overlays the personal drive on system path
- **`sum`** — SysV default or **`-r`** BSD 16-bit checksum + 512-byte block counts. - **`sum`** — SysV default or **`-r`** BSD 16-bit checksum + 512-byte block counts.
- **`uniq`** — **`-c`**, **`-d`**, **`-u`** on adjacent lines (sort input first for POSIX-style behavior). - **`uniq`** — **`-c`**, **`-d`**, **`-u`** on adjacent lines (sort input first for POSIX-style behavior).
- **`paste`** — **`-d`** delimiter list, **`-s`** serial (one files lines joined per output row). - **`paste`** — **`-d`** delimiter list, **`-s`** serial (one files lines joined per output row).
- **`split`** — **`-l`** lines or **`-b`** bytes per chunk; output basename + alphabetic suffix; max files **`BARE_OS_SPLIT_MAX_FILES`** ( **`getconf`** default **10000**). - **`split`** — **`-l`** lines or **`-b`** bytes per chunk; output basename + POSIX-style multi-length **`a``z`** suffixes (**`aa``zz`**, then **`aaa`**, **`aab`**, …); max files **`BARE_OS_SPLIT_MAX_FILES`** ( **`getconf`** default **10000**).
- **`tac`**, **`rev`** — Reverse line order / reverse characters per line. - **`tac`**, **`rev`** — Reverse line order / reverse characters per line.
- **`expand`**, **`unexpand`** — Uniform tab width (**`-t`** / **`-tN`**); spaces ↔ tabs. - **`expand`**, **`unexpand`** — Uniform tab width (**`-t`** / **`-tN`**); spaces ↔ tabs.
- **`fold`** — **`-w`** fixed column wrap (no word-aware reflow). - **`fold`** — **`-w`** fixed column wrap (no word-aware reflow).
+32 -2
View File
@@ -90,12 +90,34 @@ function bareOsEmitRaw(ctx, chunk) {
/** /**
* Move/rename via copy + delete. Hyperdrive has no single-key rename across paths, so * Move/rename via copy + delete. Hyperdrive has no single-key rename across paths, so
* directory trees and cross-location moves are duplicated then removed. A single regular * directory trees and cross-location moves are duplicated then removed. A single regular
* file to a new non-directory path uses read + write + unlink when detected below. * file to a new non-directory path uses a two-phase write: staging buffer bytes under a
* unique **`.bare-os-mv-tmp.*`** name in the **resolved destination directory**, writing the final name,
* removing the staging file, then unlinking the source — so a failed final write leaves
* the source path intact (staging is best-effort removed).
* *
* Documented limitations: cross-volume moves always copy+delete; EXDEV-style behavior is * Documented limitations: cross-volume moves always copy+delete; EXDEV-style behavior is
* implicit. Busy targets, partial copy failures, and union read-only trees surface as * implicit. Busy targets, partial copy failures, and union read-only trees surface as
* generic errors from the VFS. Prefer same-directory renames for smallest blast radius. * generic errors from the VFS. Prefer same-directory renames for smallest blast radius.
*/ */
function mvStagingPathForTarget(ctx, target) {
const raw =
ctx.vfs && typeof ctx.vfs.resolveLogical === 'function'
? ctx.vfs.resolveLogical(target)
: String(target || '')
const trimmed = String(raw || '').replace(/\/+$/, '') || '/'
const last = trimmed.lastIndexOf('/')
const dir =
last < 0 ? '/' : last === 0 ? '/' : trimmed.slice(0, last) || '/'
const base =
last < 0 ? trimmed : trimmed.slice(last + 1) || 'file'
const tag =
Date.now().toString(36) +
'-' +
Math.random().toString(36).slice(2, 10) +
Math.random().toString(36).slice(2, 6)
const name = '.bare-os-mv-tmp.' + tag + '.' + base
return dir === '/' ? '/' + name : dir + '/' + name
}
async function mvCopyPath(ctx, from, to, recursive, followSymlink) { async function mvCopyPath(ctx, from, to, recursive, followSymlink) {
const st = await ctx.vfs.lstat(from) const st = await ctx.vfs.lstat(from)
if (!st) return false if (!st) return false
@@ -206,7 +228,15 @@ async function run(ctx, argv) {
if (singleFileToFile) { if (singleFileToFile) {
const buf = await ctx.vfs.readFile(src) const buf = await ctx.vfs.readFile(src)
if (!buf) throw new Error('cannot read source') if (!buf) throw new Error('cannot read source')
await ctx.vfs.writeFile(target, buf) const stage = mvStagingPathForTarget(ctx, target)
await ctx.vfs.writeFile(stage, buf)
try {
await ctx.vfs.writeFile(target, buf)
} catch (e) {
await ctx.vfs.unlink(stage).catch(() => {})
throw e
}
await ctx.vfs.unlink(stage).catch(() => {})
await ctx.vfs.unlink(src) await ctx.vfs.unlink(src)
continue continue
} }
+20 -3
View File
@@ -87,11 +87,28 @@ function bareOsEmitRaw(ctx, chunk) {
return false return false
} }
/**
* POSIX-style suffix: `aa`…`zz` (676 files), then `aaa`, `aab`, … as needed.
* @param {string} prefix
* @param {number} i 0-based output index
*/
function splitSuffix(prefix, i) { function splitSuffix(prefix, i) {
const a = 'abcdefghijklmnopqrstuvwxyz' const a = 'abcdefghijklmnopqrstuvwxyz'
const hi = Math.floor(i / 26) % 26 let idx = i
const lo = i % 26 let len = 2
return prefix + a[hi] + a[lo] let span = 26 ** len
while (idx >= span) {
idx -= span
len++
span = 26 ** len
}
let s = ''
let n = idx
for (let p = 0; p < len; p++) {
s = a[n % 26] + s
n = Math.floor(n / 26)
}
return prefix + s
} }
async function run(ctx, argv) { async function run(ctx, argv) {
+5 -2
View File
@@ -88,11 +88,14 @@ function bareOsEmitRaw(ctx, chunk) {
} }
/** /**
* Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host spawn). * Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host fork of arbitrary binaries).
* Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation, * Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation,
* 64 invocations per run. Exceeding limits is a fatal error (exit 125). * 64 invocations per run. Exceeding limits is a fatal error (exit 125).
* Supports -0/--null, -n, -L (lines per invocation; mutually exclusive with -n), -I repl (replace repl in utility argv; implies -n 1 unless -n given). * Supports -0/--null, -n, -L (lines per invocation; mutually exclusive with -n), -I repl (replace repl in utility argv; implies -n 1 unless -n given).
* -P N runs up to N batches in parallel (each batch uses a shallow ctx clone so exitCode does not race). * -P N runs up to N batches in parallel (each batch uses a shallow ctx clone so exitCode does not race); parallelism is still in-process
* over runBinCommand unless the booter/worker stack offloads specific /bin basenames (see BARE_OS_BIN_WORKER_*).
* For explicit host subprocess offload of whitelisted utilities, use ctx.bareOsTrySpawnHostSubprocess from custom scripts with
* BARE_OS_BIN_WORKER_ALLOW / delegate policy — not automatic from xargs.
* Max -P is min(requested, BARE_OS_XARGS_MAX_PROCS env, 32); default cap 8 when env unset. * Max -P is min(requested, BARE_OS_XARGS_MAX_PROCS env, 32); default cap 8 when env unset.
*/ */
+14 -2
View File
@@ -1,6 +1,6 @@
{ {
"schemaVersion": 8, "schemaVersion": 8,
"ctxApiVersion": "1.44.0", "ctxApiVersion": "1.45.0",
"posixProfile": { "posixProfile": {
"id": "bare-os-posix-like", "id": "bare-os-posix-like",
"version": "1.0.9" "version": "1.0.9"
@@ -32,7 +32,19 @@
"namesCsv": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown" "namesCsv": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown"
}, },
"socketMsgSurface": { "socketMsgSurface": {
"schema": 2, "schema": 3,
"ancillaryControl": {
"supported": false,
"errno": "ENOTSUP",
"rejectKeys": [
"cmsgs",
"control",
"controllen",
"msgHdr.control",
"msgHdr.cmsgs"
],
"note": "Non-empty ancillary fields on sendmsg rejected; recvmsg controllen 0."
},
"sendmsg": { "bridgePartial": true, "defaultErrno": "ENOTSUP" }, "sendmsg": { "bridgePartial": true, "defaultErrno": "ENOTSUP" },
"recvmsg": { "bridgePartial": true, "defaultErrno": "ENOTSUP" } "recvmsg": { "bridgePartial": true, "defaultErrno": "ENOTSUP" }
}, },
+198 -198
View File
@@ -7,36 +7,36 @@
"hypercoreIdEncoding" "hypercoreIdEncoding"
] ]
}, },
{
"path": "/lib/bare/bundles/safetyCatch.js",
"keys": [
"safetyCatch"
]
},
{ {
"path": "/lib/bare/bundles/b4a.js", "path": "/lib/bare/bundles/b4a.js",
"keys": [ "keys": [
"b4a" "b4a"
] ]
}, },
{
"path": "/lib/bare/bundles/safetyCatch.js",
"keys": [
"safetyCatch"
]
},
{ {
"path": "/lib/bare/bundles/compactEncoding.js", "path": "/lib/bare/bundles/compactEncoding.js",
"keys": [ "keys": [
"compactEncoding" "compactEncoding"
] ]
}, },
{
"path": "/lib/bare/bundles/bareUrl.js",
"keys": [
"bareUrl"
]
},
{ {
"path": "/lib/bare/bundles/protomux.js", "path": "/lib/bare/bundles/protomux.js",
"keys": [ "keys": [
"protomux" "protomux"
] ]
}, },
{
"path": "/lib/bare/bundles/bareUrl.js",
"keys": [
"bareUrl"
]
},
{ {
"path": "/lib/bare/bundles/barePath.js", "path": "/lib/bare/bundles/barePath.js",
"keys": [ "keys": [
@@ -74,9 +74,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareAddonResolve.js", "path": "/lib/bare/bundles/bareReadline.js",
"keys": [ "keys": [
"bareAddonResolve" "bareReadline"
] ]
}, },
{ {
@@ -86,15 +86,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareReadline.js", "path": "/lib/bare/bundles/bareAddonResolve.js",
"keys": [ "keys": [
"bareReadline" "bareAddonResolve"
]
},
{
"path": "/lib/bare/bundles/bareApk.js",
"keys": [
"bareApk"
] ]
}, },
{ {
@@ -109,12 +103,6 @@
"bareAtomics" "bareAtomics"
] ]
}, },
{
"path": "/lib/bare/bundles/bareAppKit.js",
"keys": [
"bareAppKit"
]
},
{ {
"path": "/lib/bare/bundles/bareAssert.js", "path": "/lib/bare/bundles/bareAssert.js",
"keys": [ "keys": [
@@ -122,9 +110,15 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareBmp.js", "path": "/lib/bare/bundles/bareApk.js",
"keys": [ "keys": [
"bareBmp" "bareApk"
]
},
{
"path": "/lib/bare/bundles/bareAppKit.js",
"keys": [
"bareAppKit"
] ]
}, },
{ {
@@ -133,12 +127,24 @@
"fetch" "fetch"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBmp.js",
"keys": [
"bareBmp"
]
},
{ {
"path": "/lib/bare/bundles/bareBundleCompile.js", "path": "/lib/bare/bundles/bareBundleCompile.js",
"keys": [ "keys": [
"bareBundleCompile" "bareBundleCompile"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBuffer.js",
"keys": [
"bareBuffer"
]
},
{ {
"path": "/lib/bare/bundles/bareBluetoothApple.js", "path": "/lib/bare/bundles/bareBluetoothApple.js",
"keys": [ "keys": [
@@ -151,30 +157,24 @@
"bareBundle" "bareBundle"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBuffer.js",
"keys": [
"bareBuffer"
]
},
{ {
"path": "/lib/bare/bundles/bareBundleEvaluate.js", "path": "/lib/bare/bundles/bareBundleEvaluate.js",
"keys": [ "keys": [
"bareBundleEvaluate" "bareBundleEvaluate"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBoot.js",
"keys": [
"bareBoot"
]
},
{ {
"path": "/lib/bare/bundles/bareConsole.js", "path": "/lib/bare/bundles/bareConsole.js",
"keys": [ "keys": [
"bareConsole" "bareConsole"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBoot.js",
"keys": [
"bareBoot"
]
},
{ {
"path": "/lib/bare/bundles/bareBundleId.js", "path": "/lib/bare/bundles/bareBundleId.js",
"keys": [ "keys": [
@@ -187,18 +187,18 @@
"bareChannel" "bareChannel"
] ]
}, },
{
"path": "/lib/bare/bundles/bareDelta.js",
"keys": [
"bareDelta"
]
},
{ {
"path": "/lib/bare/bundles/bareDebugLog.js", "path": "/lib/bare/bundles/bareDebugLog.js",
"keys": [ "keys": [
"bareDebugLog" "bareDebugLog"
] ]
}, },
{
"path": "/lib/bare/bundles/bareDelta.js",
"keys": [
"bareDelta"
]
},
{ {
"path": "/lib/bare/bundles/bareDaemon.js", "path": "/lib/bare/bundles/bareDaemon.js",
"keys": [ "keys": [
@@ -217,6 +217,12 @@
"bareDns" "bareDns"
] ]
}, },
{
"path": "/lib/bare/bundles/bareCov.js",
"keys": [
"bareCov"
]
},
{ {
"path": "/lib/bare/bundles/bareEnv.js", "path": "/lib/bare/bundles/bareEnv.js",
"keys": [ "keys": [
@@ -235,12 +241,6 @@
"bareExif" "bareExif"
] ]
}, },
{
"path": "/lib/bare/bundles/bareCov.js",
"keys": [
"bareCov"
]
},
{ {
"path": "/lib/bare/bundles/bareFfmpeg.js", "path": "/lib/bare/bundles/bareFfmpeg.js",
"keys": [ "keys": [
@@ -260,9 +260,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareGif.js", "path": "/lib/bare/bundles/bareFileLogger.js",
"keys": [ "keys": [
"bareGif" "bareFileLogger"
] ]
}, },
{ {
@@ -272,9 +272,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareFileLogger.js", "path": "/lib/bare/bundles/bareGif.js",
"keys": [ "keys": [
"bareFileLogger" "bareGif"
] ]
}, },
{ {
@@ -290,9 +290,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareHttpParser.js", "path": "/lib/bare/bundles/bareFs.js",
"keys": [ "keys": [
"bareHttpParser" "bareFs"
] ]
}, },
{ {
@@ -301,24 +301,18 @@
"bareGtk" "bareGtk"
] ]
}, },
{
"path": "/lib/bare/bundles/bareHttpParser.js",
"keys": [
"bareHttpParser"
]
},
{ {
"path": "/lib/bare/bundles/bareIco.js", "path": "/lib/bare/bundles/bareIco.js",
"keys": [ "keys": [
"bareIco" "bareIco"
] ]
}, },
{
"path": "/lib/bare/bundles/bareFs.js",
"keys": [
"bareFs"
]
},
{
"path": "/lib/bare/bundles/bareHttp1.js",
"keys": [
"bareHttp1"
]
},
{ {
"path": "/lib/bare/bundles/bareImageResample.js", "path": "/lib/bare/bundles/bareImageResample.js",
"keys": [ "keys": [
@@ -332,9 +326,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareHttps.js", "path": "/lib/bare/bundles/bareHttp1.js",
"keys": [ "keys": [
"bareHttps" "bareHttp1"
] ]
}, },
{ {
@@ -344,9 +338,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareIpc.js", "path": "/lib/bare/bundles/bareHttps.js",
"keys": [ "keys": [
"bareIpc" "bareHttps"
] ]
}, },
{ {
@@ -355,6 +349,18 @@
"bareIntl" "bareIntl"
] ]
}, },
{
"path": "/lib/bare/bundles/bareIpc.js",
"keys": [
"bareIpc"
]
},
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{ {
"path": "/lib/bare/bundles/bareInspector.js", "path": "/lib/bare/bundles/bareInspector.js",
"keys": [ "keys": [
@@ -367,12 +373,6 @@
"bareLief" "bareLief"
] ]
}, },
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{ {
"path": "/lib/bare/bundles/bareLink.js", "path": "/lib/bare/bundles/bareLink.js",
"keys": [ "keys": [
@@ -385,30 +385,30 @@
"bareMake" "bareMake"
] ]
}, },
{
"path": "/lib/bare/bundles/bareModule.js",
"keys": [
"bareModule"
]
},
{ {
"path": "/lib/bare/bundles/bareModuleResolve.js", "path": "/lib/bare/bundles/bareModuleResolve.js",
"keys": [ "keys": [
"bareModuleResolve" "bareModuleResolve"
] ]
}, },
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{ {
"path": "/lib/bare/bundles/bareModuleTraverse.js", "path": "/lib/bare/bundles/bareModuleTraverse.js",
"keys": [ "keys": [
"bareModuleTraverse" "bareModuleTraverse"
] ]
}, },
{
"path": "/lib/bare/bundles/bareModule.js",
"keys": [
"bareModule"
]
},
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{ {
"path": "/lib/bare/bundles/bareNdk.js", "path": "/lib/bare/bundles/bareNdk.js",
"keys": [ "keys": [
@@ -439,12 +439,6 @@
"bareNet" "bareNet"
] ]
}, },
{
"path": "/lib/bare/bundles/bareMedia.js",
"keys": [
"bareMedia"
]
},
{ {
"path": "/lib/bare/bundles/bareOs.js", "path": "/lib/bare/bundles/bareOs.js",
"keys": [ "keys": [
@@ -452,15 +446,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/barePerformance.js", "path": "/lib/bare/bundles/bareMedia.js",
"keys": [ "keys": [
"barePerformance" "bareMedia"
]
},
{
"path": "/lib/bare/bundles/barePackDrive.js",
"keys": [
"barePackDrive"
] ]
}, },
{ {
@@ -469,12 +457,30 @@
"barePack" "barePack"
] ]
}, },
{
"path": "/lib/bare/bundles/barePerformance.js",
"keys": [
"barePerformance"
]
},
{
"path": "/lib/bare/bundles/bareNodeRuntime.js",
"keys": [
"bareNodeRuntime"
]
},
{ {
"path": "/lib/bare/bundles/barePng.js", "path": "/lib/bare/bundles/barePng.js",
"keys": [ "keys": [
"barePng" "barePng"
] ]
}, },
{
"path": "/lib/bare/bundles/barePackDrive.js",
"keys": [
"barePackDrive"
]
},
{ {
"path": "/lib/bare/bundles/barePipe.js", "path": "/lib/bare/bundles/barePipe.js",
"keys": [ "keys": [
@@ -488,15 +494,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareNodeRuntime.js", "path": "/lib/bare/bundles/bareQuerystring.js",
"keys": [ "keys": [
"bareNodeRuntime" "bareQuerystring"
]
},
{
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareDev"
] ]
}, },
{ {
@@ -506,9 +506,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareQuerystring.js", "path": "/lib/bare/bundles/bareQueueMicrotask.js",
"keys": [ "keys": [
"bareQuerystring" "bareQueueMicrotask"
] ]
}, },
{ {
@@ -523,24 +523,12 @@
"bareProcess" "bareProcess"
] ]
}, },
{
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
"keys": [
"bareQueueMicrotask"
]
},
{ {
"path": "/lib/bare/bundles/barePromClient.js", "path": "/lib/bare/bundles/barePromClient.js",
"keys": [ "keys": [
"barePromClient" "barePromClient"
] ]
}, },
{
"path": "/lib/bare/bundles/bareRpc.js",
"keys": [
"bareRpc"
]
},
{ {
"path": "/lib/bare/bundles/bareRuntime.js", "path": "/lib/bare/bundles/bareRuntime.js",
"keys": [ "keys": [
@@ -548,15 +536,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareSemver.js", "path": "/lib/bare/bundles/bareRpc.js",
"keys": [ "keys": [
"bareSemver" "bareRpc"
]
},
{
"path": "/lib/bare/bundles/bareSdl.js",
"keys": [
"bareSdl"
] ]
}, },
{ {
@@ -565,6 +547,18 @@
"bareRepl" "bareRepl"
] ]
}, },
{
"path": "/lib/bare/bundles/bareSemver.js",
"keys": [
"bareSemver"
]
},
{
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareDev"
]
},
{ {
"path": "/lib/bare/bundles/bareSidecar.js", "path": "/lib/bare/bundles/bareSidecar.js",
"keys": [ "keys": [
@@ -577,6 +571,12 @@
"bareSignals" "bareSignals"
] ]
}, },
{
"path": "/lib/bare/bundles/bareSdl.js",
"keys": [
"bareSdl"
]
},
{ {
"path": "/lib/bare/bundles/bareRun.js", "path": "/lib/bare/bundles/bareRun.js",
"keys": [ "keys": [
@@ -589,60 +589,60 @@
"bareStringDecoder" "bareStringDecoder"
] ]
}, },
{
"path": "/lib/bare/bundles/bareStorage.js",
"keys": [
"bareStorage"
]
},
{ {
"path": "/lib/bare/bundles/bareStream.js", "path": "/lib/bare/bundles/bareStream.js",
"keys": [ "keys": [
"bareStream" "bareStream"
] ]
}, },
{
"path": "/lib/bare/bundles/bareStdio.js",
"keys": [
"bareStdio"
]
},
{ {
"path": "/lib/bare/bundles/bareSvg.js", "path": "/lib/bare/bundles/bareSvg.js",
"keys": [ "keys": [
"bareSvg" "bareSvg"
] ]
}, },
{
"path": "/lib/bare/bundles/bareStdio.js",
"keys": [
"bareStdio"
]
},
{
"path": "/lib/bare/bundles/bareStorage.js",
"keys": [
"bareStorage"
]
},
{ {
"path": "/lib/bare/bundles/bareStructuredClone.js", "path": "/lib/bare/bundles/bareStructuredClone.js",
"keys": [ "keys": [
"bareStructuredClone" "bareStructuredClone"
] ]
}, },
{
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareSystemLogger"
]
},
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{ {
"path": "/lib/bare/bundles/bareTiff.js", "path": "/lib/bare/bundles/bareTiff.js",
"keys": [ "keys": [
"bareTiff" "bareTiff"
] ]
}, },
{
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareSystemLogger"
]
},
{ {
"path": "/lib/bare/bundles/bareSubprocess.js", "path": "/lib/bare/bundles/bareSubprocess.js",
"keys": [ "keys": [
"bareSubprocess" "bareSubprocess"
] ]
}, },
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{ {
"path": "/lib/bare/bundles/bareTcp.js", "path": "/lib/bare/bundles/bareTcp.js",
"keys": [ "keys": [
@@ -655,18 +655,18 @@
"bareThread" "bareThread"
] ]
}, },
{
"path": "/lib/bare/bundles/bareTimers.js",
"keys": [
"bareTimers"
]
},
{ {
"path": "/lib/bare/bundles/bareTpl.js", "path": "/lib/bare/bundles/bareTpl.js",
"keys": [ "keys": [
"bareTpl" "bareTpl"
] ]
}, },
{
"path": "/lib/bare/bundles/bareTimers.js",
"keys": [
"bareTimers"
]
},
{ {
"path": "/lib/bare/bundles/bareType.js", "path": "/lib/bare/bundles/bareType.js",
"keys": [ "keys": [
@@ -691,12 +691,6 @@
"bareTty" "bareTty"
] ]
}, },
{
"path": "/lib/bare/bundles/bareV8.js",
"keys": [
"bareV8"
]
},
{ {
"path": "/lib/bare/bundles/bareUnpack.js", "path": "/lib/bare/bundles/bareUnpack.js",
"keys": [ "keys": [
@@ -704,9 +698,15 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareUnionBundle.js", "path": "/lib/bare/bundles/bareV8.js",
"keys": [ "keys": [
"bareUnionBundle" "bareV8"
]
},
{
"path": "/lib/bare/bundles/bareVm.js",
"keys": [
"bareVm"
] ]
}, },
{ {
@@ -722,21 +722,15 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareVm.js", "path": "/lib/bare/bundles/bareUnionBundle.js",
"keys": [ "keys": [
"bareVm" "bareUnionBundle"
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareUtils.js", "path": "/lib/bare/bundles/bareV8ToIstanbul.js",
"keys": [ "keys": [
"bareUtils" "bareV8ToIstanbul"
]
},
{
"path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [
"bareWebKitGtk"
] ]
}, },
{ {
@@ -745,6 +739,12 @@
"bareWebp" "bareWebp"
] ]
}, },
{
"path": "/lib/bare/bundles/bareUtils.js",
"keys": [
"bareUtils"
]
},
{ {
"path": "/lib/bare/bundles/bareWhich.js", "path": "/lib/bare/bundles/bareWhich.js",
"keys": [ "keys": [
@@ -752,15 +752,15 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareWinUi.js", "path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [ "keys": [
"bareWinUi" "bareWebKitGtk"
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareV8ToIstanbul.js", "path": "/lib/bare/bundles/bareWinUi.js",
"keys": [ "keys": [
"bareV8ToIstanbul" "bareWinUi"
] ]
}, },
{ {
@@ -775,6 +775,12 @@
"bareZlib" "bareZlib"
] ]
}, },
{
"path": "/lib/bare/bundles/bareWs.js",
"keys": [
"bareWs"
]
},
{ {
"path": "/lib/bare/bundles/bareZmq.js", "path": "/lib/bare/bundles/bareZmq.js",
"keys": [ "keys": [
@@ -786,12 +792,6 @@
"keys": [ "keys": [
"bareWorker" "bareWorker"
] ]
},
{
"path": "/lib/bare/bundles/bareWs.js",
"keys": [
"bareWs"
]
} }
], ],
"bundleStats": { "bundleStats": {
@@ -1595,8 +1595,8 @@
], ],
"bundleProvenance": { "bundleProvenance": {
"schemaVersion": 1, "schemaVersion": 1,
"generatedAt": "2026-04-05T05:06:01.462Z", "generatedAt": "2026-04-05T05:30:46.127Z",
"gitCommit": "f79db043130bdbfffa8bcca66fd6252c9d17205d", "gitCommit": "c64910d72ee5547302fce1717ffedd42594e4bc4",
"nodeVersion": "v22.22.0", "nodeVersion": "v22.22.0",
"bundleTier": "all", "bundleTier": "all",
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json", "normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"schema": 1, "schema": 1,
"atMs": 1775365560517, "atMs": 1775367045352,
"commands": [ "commands": [
"arch", "arch",
"awk", "awk",
File diff suppressed because one or more lines are too long
+4 -1
View File
@@ -5,17 +5,20 @@ Authoritative **version alignment** with protocol and telemetry schema numbers l
## Maintenance ## Maintenance
- **Host filesystem**: first-party booter and seeder sources use **`import … from '#host-fs'`** / **`#host-path`** (and seeder **`#host-fs-promises`**) so Bare resolves **`bare-fs`** / **`bare-path`** and Node resolves the built-in **`fs`** / **`path`** modules via the default **`imports`** condition. **`bare-fs`** is a direct **`dependencies`** entry of **`bare-os-booter`**. CI: **`scripts/verify-pear-no-static-node-import.mjs`** rejects bare **`fs`** / **`path`** specifiers. - **Host filesystem**: first-party booter and seeder sources use **`import … from '#host-fs'`** / **`#host-path`** (and seeder **`#host-fs-promises`**) so Bare resolves **`bare-fs`** / **`bare-path`** and Node resolves the built-in **`fs`** / **`path`** modules via the default **`imports`** condition. **`bare-fs`** is a direct **`dependencies`** entry of **`bare-os-booter`**. CI: **`scripts/verify-pear-no-static-node-import.mjs`** rejects bare **`fs`** / **`path`** specifiers.
- **POSIX / proc**: **`/proc/bare_os/syscalls.json`** schema **5** (socket-family probes, **`posixXsh`** / **`fdModel`** / **`errnoAlignment`**; JSON text **cached** until **`vfs.bareOsClearWarmReadCaches`**); **`/proc/bare_os/process_table.json`** schema **6** (**`jobControlSemantics`** + **`parentName`**); **`/proc/bare_os/protomux.json`** wire text schema **2**; **`/dev/shm`** in-memory named segments. Protocol export **`BARE_OS_POSIX_PROFILE_*`**. - **POSIX / proc**: **`/proc/bare_os/syscalls.json`** schema **8** (**`posixXsh`**, **`fdModel`**, **`socketMsgSurface`**, **`errnoHints`**; JSON text **cached** until **`vfs.bareOsClearWarmReadCaches`**); **`/proc/bare_os/process_table.json`** schema **7**; **`/proc/bare_os/protomux.json`** wire text schema **2**; **`/dev/shm`** in-memory named segments. Protocol export **`BARE_OS_POSIX_PROFILE_*`**.
- **Blind-relay / pairing / geo proc** (default): **`bareOsProcBlindPeerRelayHintsMinimal`** returns **schema 1** with **`operatorRedacted: true`**. The legacy export **`bareOsProcBlindPeerRelayHintsStub`** was removed; use **`bareOsProcBlindPeerRelayHintsMinimal`** only. - **Blind-relay / pairing / geo proc** (default): **`bareOsProcBlindPeerRelayHintsMinimal`** returns **schema 1** with **`operatorRedacted: true`**. The legacy export **`bareOsProcBlindPeerRelayHintsStub`** was removed; use **`bareOsProcBlindPeerRelayHintsMinimal`** only.
- **Vendored bundles**: post-esbuild **`scripts/sanitize-bare-bundles.mjs`** (from **`bare-os-bare-libs/build.mjs`**) strips CI-forbidden markers and replaces **`node:`** requires in **`bareDev.js`** with **`bare-*`** modules. - **Vendored bundles**: post-esbuild **`scripts/sanitize-bare-bundles.mjs`** (from **`bare-os-bare-libs/build.mjs`**) strips CI-forbidden markers and replaces **`node:`** requires in **`bareDev.js`** with **`bare-*`** modules.
- **Boot hooks (naming)**: canonical **`bareOsRegisterBootStepHook`**, **`bareOsInvokeBootStepHooks`**, **`bareOsEmitBareBootStepHint`**; legacy **`*BootPhase*`** methods remain thin wrappers (**no `bareOsCtxApiVersion` bump**). See [docs/reference/naming-alias-matrix.md](../../docs/reference/naming-alias-matrix.md). - **Boot hooks (naming)**: canonical **`bareOsRegisterBootStepHook`**, **`bareOsInvokeBootStepHooks`**, **`bareOsEmitBareBootStepHint`**; legacy **`*BootPhase*`** methods remain thin wrappers (**no `bareOsCtxApiVersion` bump**). See [docs/reference/naming-alias-matrix.md](../../docs/reference/naming-alias-matrix.md).
- **Pear / Bare**: [`lib/kernel-runner.js`](lib/kernel-runner.js) must not **static**-import **`node:module`** (Bares resolver cannot load **`node:`** builtins from a **`pear://`** bundle). Optional **`BARE_OS_BIN_WORKER_OFFLOAD`** now obtains **`createRequire`** via **dynamic** **`import('bare-module')`** when running outside Node. - **Pear / Bare**: [`lib/kernel-runner.js`](lib/kernel-runner.js) must not **static**-import **`node:module`** (Bares resolver cannot load **`node:`** builtins from a **`pear://`** bundle). Optional **`BARE_OS_BIN_WORKER_OFFLOAD`** now obtains **`createRequire`** via **dynamic** **`import('bare-module')`** when running outside Node.
- **`baretop`**: optional **`ctx.bareOsReadBareTopSnapshot()`** in [`index.js`](index.js) returns **`{ atMs, files }`** with the same keys as **`BARE_TOP_SNAPSHOT_PROC_ENTRIES`** in **`packages/bare-os-coreutils/lib/baretop-snapshot.js`** — keep those lists in sync when adding operator **`/proc/bare_os`** nodes. - **`baretop`**: optional **`ctx.bareOsReadBareTopSnapshot()`** in [`index.js`](index.js) returns **`{ atMs, files }`** with the same keys as **`BARE_TOP_SNAPSHOT_PROC_ENTRIES`** in **`packages/bare-os-coreutils/lib/baretop-snapshot.js`** — keep those lists in sync when adding operator **`/proc/bare_os`** nodes.
- **hrpc allowlist**: shared parser in [`lib/bare-os-hrpc-allowlist.js`](lib/bare-os-hrpc-allowlist.js); **`ctx.bareOsHrpcRequest`** and **`ctx.bareOsHrpcAllowlistProbe`** stay aligned. Host passthrough copies **`BARE_OS_HRPC_ALLOWLIST_JSON`**, **`BARE_OS_CORESTORE_SNAPSHOT_WORKFLOW_JSON`**, **`BARE_OS_BLIND_RELAY_TOPOLOGY_JSON`**, **`BARE_OS_MIRROR_DRIVE_COMPOSITION_HINT_JSON`**, **`BARE_OS_REPLICATION_PLAN_JSON`**, and pear-doctor env keys into session env.
- **Snapshot hints**: **`ctx.bareOsReadSnapshotHintsJson()`** merges **`BARE_OS_CORESTORE_SNAPSHOT_WORKFLOW_JSON`** like **`/proc/bare_os/snapshot_hints.json`**.
## Context API (`bareOsCtxApiVersion`) ## Context API (`bareOsCtxApiVersion`)
| Version | Booter (workspace) | Notes | | Version | Booter (workspace) | Notes |
| ------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 1.45.0 | 0.1.0 | **`BARE_OS_POSIX_SOCKET_FD_BRIDGE`**: SOCK_STREAM passive **`bind`** / **`listen`** / **`accept`** via **`bareTcp.Server`**; accepted fds use **`send`** / **`recv`** / **`recvfrom`** / **`recvmsg`** with bounded **`tcpRecvQueue`** (same cap family as **`BARE_OS_POSIX_DGRAM_RECVQ_MAX`**); **`poll`/`select`** marks listening fds readable when the accept queue is non-empty; **`BARE_OS_POSIX_ACCEPT_QUEUE_MAX`** caps pending accepts. **`socketMsgSurface` schema 3** adds **`ancillaryControl`** and rejects non-empty **`sendmsg`** ancillary fields with **`ENOTSUP`** + **`ancillaryReject`**. **`shutdown`** closes a listening server or destroys a connected TCP bridge socket. |
| 1.42.0 | 0.1.0 | **`BARE_OS_POSIX_SOCKET_FD_BRIDGE`**: SOCK_DGRAM **`recv`** / **`recvfrom`** with bounded queue (**`BARE_OS_POSIX_DGRAM_RECVQ_MAX`**, **`BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX`**); **`poll`/`select`** readiness on bridge UDP fds. **`/proc/bare_os/syscalls.json`** schema **7** + **`socketMsgSurface`**. Optional **`BARE_OS_PROTOMUX_APP_CHANNEL`** pairs **`bare-os-app-v1`** alongside **`bare-os-v1`**. **`guestReplicationPlan`** in **`/proc/bare_os/replication`** from **`BARE_OS_REPLICATION_PLAN_JSON`**. **`sync_window.json`** **`parallelismHint`** (**`BARE_OS_REPLICATION_SYNC_PARALLEL_MAX`**). Blind-relay swarm **`protomuxBackpressure`** (**`BARE_OS_SWARM_PROTOMUX_BACKPRESSURE_COUNT`**). **`BARE_OS_PEER_ALLOWLIST_STRICT`** fail-closed without allowlist. Removed **`bareOsProcBlindPeerRelayHintsStub`** (use **`bareOsProcBlindPeerRelayHintsMinimal`**). Kernel: optional **`pear.multisig.json`** gate before **`kernel.ext.d`** (**`BARE_OS_EXTENSION_MULTISIG_VERIFY`**, **`BARE_OS_BOOT_POLICY_REQUIRE_PEAR_MULTISIG`**). | | 1.42.0 | 0.1.0 | **`BARE_OS_POSIX_SOCKET_FD_BRIDGE`**: SOCK_DGRAM **`recv`** / **`recvfrom`** with bounded queue (**`BARE_OS_POSIX_DGRAM_RECVQ_MAX`**, **`BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX`**); **`poll`/`select`** readiness on bridge UDP fds. **`/proc/bare_os/syscalls.json`** schema **7** + **`socketMsgSurface`**. Optional **`BARE_OS_PROTOMUX_APP_CHANNEL`** pairs **`bare-os-app-v1`** alongside **`bare-os-v1`**. **`guestReplicationPlan`** in **`/proc/bare_os/replication`** from **`BARE_OS_REPLICATION_PLAN_JSON`**. **`sync_window.json`** **`parallelismHint`** (**`BARE_OS_REPLICATION_SYNC_PARALLEL_MAX`**). Blind-relay swarm **`protomuxBackpressure`** (**`BARE_OS_SWARM_PROTOMUX_BACKPRESSURE_COUNT`**). **`BARE_OS_PEER_ALLOWLIST_STRICT`** fail-closed without allowlist. Removed **`bareOsProcBlindPeerRelayHintsStub`** (use **`bareOsProcBlindPeerRelayHintsMinimal`**). Kernel: optional **`pear.multisig.json`** gate before **`kernel.ext.d`** (**`BARE_OS_EXTENSION_MULTISIG_VERIFY`**, **`BARE_OS_BOOT_POLICY_REQUIRE_PEAR_MULTISIG`**). |
| 1.41.0 | 0.1.0 | **`BARE_OS_BARE_STDLIB_RESOLVE_CONCURRENCY`** — parallel **`readFile`** prefetch for **`/lib/bare`** drive bundles; eval order stays manifest order. **`vfs.bareOsEvictWarmReadPrefixes`** + **`BARE_OS_VFS_WARM_CACHE_PREFIX_INVALIDATE`** — selective warm-cache eviction when replication core lengths increase; **`metrics_live.replicationLive`** schema **2**. Stock **`ctx.bareOsHrpcRequest`**: optional **`BARE_OS_HRPC_AUDIT`** (audit chain rows), **`BARE_OS_HRPC_EMIT_UNLISTED`** gates **`bare-os:hrpc-request`** for non-stock routes (default off). **`/proc/bare_os/pear_runtime_channel.json`** (word 7). Warm read cache stats schema **2**; gated **`BARE_OS_VFS_HYPERBLOBS_DEDUP`** write telemetry + failure counter. | | 1.41.0 | 0.1.0 | **`BARE_OS_BARE_STDLIB_RESOLVE_CONCURRENCY`** — parallel **`readFile`** prefetch for **`/lib/bare`** drive bundles; eval order stays manifest order. **`vfs.bareOsEvictWarmReadPrefixes`** + **`BARE_OS_VFS_WARM_CACHE_PREFIX_INVALIDATE`** — selective warm-cache eviction when replication core lengths increase; **`metrics_live.replicationLive`** schema **2**. Stock **`ctx.bareOsHrpcRequest`**: optional **`BARE_OS_HRPC_AUDIT`** (audit chain rows), **`BARE_OS_HRPC_EMIT_UNLISTED`** gates **`bare-os:hrpc-request`** for non-stock routes (default off). **`/proc/bare_os/pear_runtime_channel.json`** (word 7). Warm read cache stats schema **2**; gated **`BARE_OS_VFS_HYPERBLOBS_DEDUP`** write telemetry + failure counter. |
| 1.40.0 | 0.1.0 | **`vfs.bareOsEvictLibBareBundlesFromManifest`** + **`ctx.bareOsInvalidateWarmReadCachesFromBareManifestJson`** — manifest-aware **`/lib/bare`** warm-cache eviction; **`bareOsVfsBatchWrite`** uses selective eviction for manifest-only puts. **`/proc/bare_os/replication`** **`liveHyperdrive`** sketch + **`metrics_live.replicationLive`** (**`stallHint`**, core lengths). **`/run/bare-os/boot-perf.json`** schema **3** + **`BARE_OS_BOOT_BUDGET_STDLIB_*`** when bare-stdlib resolution exceeds **`BARE_OS_BOOT_BUDGET_MS_COLD`** / **`BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB`**. **`BARE_OS_SHELL_POSIX_MODE`** grouped **`( … )`** lists. **`bareOsTrySpawnHostSubprocess`** failures include **`errorCode`** / **`causeName`**. NDJSON / OTel string redaction helpers. **`scripts/sync-holepunch-clones.mjs`** NDJSON summary. **`docs/reference/posix-dashboard.md`** generated in pretest. | | 1.40.0 | 0.1.0 | **`vfs.bareOsEvictLibBareBundlesFromManifest`** + **`ctx.bareOsInvalidateWarmReadCachesFromBareManifestJson`** — manifest-aware **`/lib/bare`** warm-cache eviction; **`bareOsVfsBatchWrite`** uses selective eviction for manifest-only puts. **`/proc/bare_os/replication`** **`liveHyperdrive`** sketch + **`metrics_live.replicationLive`** (**`stallHint`**, core lengths). **`/run/bare-os/boot-perf.json`** schema **3** + **`BARE_OS_BOOT_BUDGET_STDLIB_*`** when bare-stdlib resolution exceeds **`BARE_OS_BOOT_BUDGET_MS_COLD`** / **`BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB`**. **`BARE_OS_SHELL_POSIX_MODE`** grouped **`( … )`** lists. **`bareOsTrySpawnHostSubprocess`** failures include **`errorCode`** / **`causeName`**. NDJSON / OTel string redaction helpers. **`scripts/sync-holepunch-clones.mjs`** NDJSON summary. **`docs/reference/posix-dashboard.md`** generated in pretest. |
+673 -57
View File
@@ -78,6 +78,10 @@ import { buildBareOsBareModuleCryptoStagingProcJson } from './lib/bare-os-proc-b
import { buildBareOsPearInspectLoggerTlsProcJson } from './lib/bare-os-proc-pear-inspect-logger-tls.js' import { buildBareOsPearInspectLoggerTlsProcJson } from './lib/bare-os-proc-pear-inspect-logger-tls.js'
import { buildBareOsHypercorePackHrpcLifecycleProcJson } from './lib/bare-os-proc-hypercore-pack-hrpc-lifecycle.js' import { buildBareOsHypercorePackHrpcLifecycleProcJson } from './lib/bare-os-proc-hypercore-pack-hrpc-lifecycle.js'
import { createBareOsIpc } from './lib/bare-os-ipc.js' import { createBareOsIpc } from './lib/bare-os-ipc.js'
import {
parseBareOsHrpcAllowlistJson,
bareOsHrpcAllowlistDeniesRoute
} from './lib/bare-os-hrpc-allowlist.js'
import { import {
execShellLine, execShellLine,
syncBareOsExitStatusEnv, syncBareOsExitStatusEnv,
@@ -621,6 +625,14 @@ async function executeKernel(disk, store, swarm, initSource) {
'BARE_OS_VFS_WARM_CACHE_PREFIX_INVALIDATE', 'BARE_OS_VFS_WARM_CACHE_PREFIX_INVALIDATE',
'BARE_OS_HRPC_AUDIT', 'BARE_OS_HRPC_AUDIT',
'BARE_OS_HRPC_EMIT_UNLISTED', 'BARE_OS_HRPC_EMIT_UNLISTED',
'BARE_OS_HRPC_ALLOWLIST_JSON',
'BARE_OS_CORESTORE_SNAPSHOT_WORKFLOW_JSON',
'BARE_OS_BLIND_RELAY_TOPOLOGY_JSON',
'BARE_OS_MIRROR_DRIVE_COMPOSITION_HINT_JSON',
'BARE_OS_REPLICATION_PLAN_JSON',
'BARE_OS_PEAR_DOCTOR_STATE_JSON',
'BARE_OS_PEAR_INSPECT_PROBE',
'BARE_OS_PEAR_DOCTOR_MODULE',
'BARE_OS_HYPERDHT_STATS_JSON', 'BARE_OS_HYPERDHT_STATS_JSON',
'BARE_OS_RUNBIN_DEFAULT_TIMEOUT_MS', 'BARE_OS_RUNBIN_DEFAULT_TIMEOUT_MS',
'BARE_OS_VFS_SNAPSHOTS', 'BARE_OS_VFS_SNAPSHOTS',
@@ -1826,7 +1838,38 @@ async function executeKernel(disk, store, swarm, initSource) {
skewEstimateMs: null, skewEstimateMs: null,
source: 'host', source: 'host',
note: 'Optional NTP or peer RTT skew may populate skewEstimateMs in future releases.' note: 'Optional NTP or peer RTT skew may populate skewEstimateMs in future releases.'
} },
blindRelayTopology: (() => {
const raw = String(
shellEnv.BARE_OS_BLIND_RELAY_TOPOLOGY_JSON || ''
).trim()
if (!raw) return undefined
try {
const o = JSON.parse(raw)
if (!o || typeof o !== 'object' || Array.isArray(o)) {
return { schema: 1, note: 'invalid_shape' }
}
const relay = /** @type {Record<string, unknown>} */ (o)
return {
schema: 1,
relayServicePresent: relay.relayServicePresent === true,
routerHintTier:
typeof relay.routerHintTier === 'number'
? Math.min(99, Math.max(0, Math.floor(relay.routerHintTier)))
: undefined,
pairingChannelCount:
typeof relay.pairingChannelCount === 'number'
? Math.min(
9999,
Math.max(0, Math.floor(relay.pairingChannelCount))
)
: undefined,
note: 'PII-free sketch from BARE_OS_BLIND_RELAY_TOPOLOGY_JSON for blind-relay / router operators.'
}
} catch {
return { schema: 1, parseError: true }
}
})()
})}\n` })}\n`
}, },
procBareOsReplicationText() { procBareOsReplicationText() {
@@ -1840,6 +1883,33 @@ async function executeKernel(disk, store, swarm, initSource) {
liveHyperdrive: buildBareOsReplicationLiveSketch(disk, peers), liveHyperdrive: buildBareOsReplicationLiveSketch(disk, peers),
session: sessionStatsRef, session: sessionStatsRef,
mirrorHint: !!(mk && String(mk).trim()), mirrorHint: !!(mk && String(mk).trim()),
mirrorDriveCompositionHint: (() => {
const raw = String(
shellEnv.BARE_OS_MIRROR_DRIVE_COMPOSITION_HINT_JSON || ''
).trim()
if (!raw) return undefined
try {
const o = JSON.parse(raw)
if (!o || typeof o !== 'object' || Array.isArray(o)) {
return { schema: 1, note: 'invalid_shape' }
}
const h = /** @type {Record<string, unknown>} */ (o)
return {
schema: 1,
mirrorDrivePattern:
typeof h.mirrorDrivePattern === 'string'
? String(h.mirrorDrivePattern).slice(0, 256)
: undefined,
auxiliaryCountHint:
typeof h.auxiliaryCountHint === 'number'
? Math.min(99, Math.max(0, Math.floor(h.auxiliaryCountHint)))
: undefined,
note: 'Operator sketch from BARE_OS_MIRROR_DRIVE_COMPOSITION_HINT_JSON (mirror-drivestyle composition).'
}
} catch {
return { schema: 1, parseError: true }
}
})(),
seedReplication: sr && typeof sr === 'object' ? sr : undefined, seedReplication: sr && typeof sr === 'object' ? sr : undefined,
seedManifestHints: seedManifestHints:
disk.seedManifestHints && typeof disk.seedManifestHints === 'object' disk.seedManifestHints && typeof disk.seedManifestHints === 'object'
@@ -2172,6 +2242,19 @@ async function executeKernel(disk, store, swarm, initSource) {
h && typeof h === 'object' && !Array.isArray(h) ? { ...h } : { schema: 1 } h && typeof h === 'object' && !Array.isArray(h) ? { ...h } : { schema: 1 }
o.atMs = Date.now() o.atMs = Date.now()
if (handles.length) o.snapshot_handles = handles if (handles.length) o.snapshot_handles = handles
const wfRaw = String(
shellEnv.BARE_OS_CORESTORE_SNAPSHOT_WORKFLOW_JSON || ''
).trim()
if (wfRaw) {
try {
const w = JSON.parse(wfRaw)
if (w && typeof w === 'object' && !Array.isArray(w)) {
o.corestoreSnapshotWorkflow = w
}
} catch {
o.corestoreSnapshotWorkflowParseError = true
}
}
return `${JSON.stringify(o)}\n` return `${JSON.stringify(o)}\n`
}, },
procBareOsProvenanceText() { procBareOsProvenanceText() {
@@ -2830,39 +2913,15 @@ async function executeKernel(disk, store, swarm, initSource) {
}) })
} }
const allowRaw = String(shellEnv.BARE_OS_HRPC_ALLOWLIST_JSON || '').trim() const allowParsed = parseBareOsHrpcAllowlistJson(
if (allowRaw) { String(shellEnv.BARE_OS_HRPC_ALLOWLIST_JSON || '')
try { )
const parsed = JSON.parse(allowRaw) if (allowParsed.parseError) {
/** @type {Set<string>} */ throw new Error('bareOsHrpcRequest: invalid BARE_OS_HRPC_ALLOWLIST_JSON')
const allow = new Set() }
if (Array.isArray(parsed)) { if (bareOsHrpcAllowlistDeniesRoute(allowParsed.allow, svc, m)) {
for (const v of parsed) { hrpcAuditAppend({ ok: false, reason: 'allowlist_denied' })
const s = String(v || '').trim() throw new Error('bareOsHrpcRequest: method denied by allowlist')
if (s) allow.add(s)
}
} else if (parsed && typeof parsed === 'object') {
for (const [k, v] of Object.entries(parsed)) {
if (v) allow.add(String(k).trim())
}
}
if (allow.size > 0) {
const key = `${svc}.${m}`
if (!allow.has('*') && !allow.has(`${svc}.*`) && !allow.has(key)) {
hrpcAuditAppend({ ok: false, reason: 'allowlist_denied' })
throw new Error('bareOsHrpcRequest: method denied by allowlist')
}
}
} catch (e) {
if (
e &&
typeof e === 'object' &&
String(e.message || '').includes('allowlist')
) {
throw e
}
throw new Error('bareOsHrpcRequest: invalid BARE_OS_HRPC_ALLOWLIST_JSON')
}
} }
if (svc === 'kernel' && m === 'ping') { if (svc === 'kernel' && m === 'ping') {
@@ -2987,6 +3046,38 @@ async function executeKernel(disk, store, swarm, initSource) {
return 30000 return 30000
} }
function bareOsPosixAcceptQueueMax(env) {
const n = Math.floor(Number(String(env?.BARE_OS_POSIX_ACCEPT_QUEUE_MAX ?? '').trim()) || 0)
const v = n > 0 ? n : 64
return Math.min(1024, Math.max(1, v))
}
function bareOsPosixAcceptBlockMsMax(env) {
return bareOsPosixDgramRecvBlockMsMax(env)
}
/**
* Non-empty ancillary / control payloads are rejected with ENOTSUP (schema 3 contract).
* @param {Record<string, unknown>} args
* @returns {string | null} reject reason key for diagnostics, or null if absent/empty
*/
function bareOsSendmsgAncillaryRejectReason(args) {
if (!args || typeof args !== 'object') return null
if (Array.isArray(args.cmsgs) && args.cmsgs.length > 0) return 'cmsgs'
const ctl = args.control
if (ctl instanceof Uint8Array && ctl.byteLength > 0) return 'control'
const clen = Number(args.controllen)
if (Number.isFinite(clen) && clen > 0) return 'controllen'
const mh = args.msgHdr
if (mh && typeof mh === 'object') {
const mhc = /** @type {Record<string, unknown>} */ (mh).control
if (mhc instanceof Uint8Array && mhc.byteLength > 0) return 'msgHdr.control'
const c2 = /** @type {Record<string, unknown>} */ (mh).cmsgs
if (Array.isArray(c2) && c2.length > 0) return 'msgHdr.cmsgs'
}
return null
}
/** /**
* Flatten sendmsg iovec list (bounded) for the SOCK_DGRAM bridge. * Flatten sendmsg iovec list (bounded) for the SOCK_DGRAM bridge.
* @param {Record<string, unknown>} args * @param {Record<string, unknown>} args
@@ -4002,6 +4093,23 @@ async function executeKernel(disk, store, swarm, initSource) {
) { ) {
ready.push({ fd, revents: 'r' }) ready.push({ fd, revents: 'r' })
} }
if (
bridge &&
bridge.state === 'connected' &&
bridge.transport === 'tcp' &&
Array.isArray(bridge.tcpRecvQueue) &&
bridge.tcpRecvQueue.length > 0
) {
ready.push({ fd, revents: 'r' })
}
if (
bridge &&
bridge.state === 'listening' &&
Array.isArray(bridge.acceptQueue) &&
bridge.acceptQueue.length > 0
) {
ready.push({ fd, revents: 'r' })
}
} }
} }
return { ok: true, ready, waitedMs: 0 } return { ok: true, ready, waitedMs: 0 }
@@ -5148,20 +5256,342 @@ async function executeKernel(disk, store, swarm, initSource) {
transport: 'tcp' transport: 'tcp'
} }
} }
if ( if (name === 'bind') {
name === 'bind' || const fd = Number(args.fd)
name === 'listen' || if (!Number.isFinite(fd)) {
name === 'accept' || return {
name === 'shutdown' ok: false,
) { op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'bind: fd required'
}
}
const k = String(fd >>> 0)
const slot =
this.bareOsSocketBridgeByFd &&
typeof this.bareOsSocketBridgeByFd === 'object'
? this.bareOsSocketBridgeByFd[k]
: null
const isDgram = Number(slot?.sockType ?? slot?.type ?? 1) === 2
if (isDgram) {
return {
ok: false,
op: name,
code: 'ENOTSUP',
errnoHint: 'ENOTSUP',
posixAlignment: 'ENOTSUP',
note:
'bind: SOCK_DGRAM bridge uses connect(); passive UDP bind is not implemented.'
}
}
if (!slot || slot.state !== 'created') {
return {
ok: false,
op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'bind: requires SOCK_STREAM bridge socket in created state.'
}
}
const port = Number(args.port)
const host = String(
args.host || args.address || '0.0.0.0'
).trim() || '0.0.0.0'
if (!Number.isFinite(port) || port < 0 || port > 65535) {
return {
ok: false,
op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'bind: port required (065535)'
}
}
slot.bindPort = port
slot.bindHost = host
slot.state = 'bound'
this.bareOsLogicalFds[k] =
'bare-os-socket-bridge:tcp-bound:' + host + ':' + port
return {
ok: true,
op: name,
fd,
bridge: true,
posixAlignment: 'partial',
port,
host
}
}
if (name === 'listen') {
const fd = Number(args.fd)
if (!Number.isFinite(fd)) {
return {
ok: false,
op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'listen: fd required'
}
}
const k = String(fd >>> 0)
const slot =
this.bareOsSocketBridgeByFd &&
typeof this.bareOsSocketBridgeByFd === 'object'
? this.bareOsSocketBridgeByFd[k]
: null
if (!slot || slot.state !== 'bound') {
return {
ok: false,
op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'listen: call bind(2) on the bridge fd first.'
}
}
const TcpServer =
bareLibrary.bareTcp &&
bareLibrary.bareTcp.Server &&
typeof bareLibrary.bareTcp.Server === 'function'
? bareLibrary.bareTcp.Server
: null
if (!TcpServer) {
return {
ok: false,
op: name,
code: 'ENOTSUP',
errnoHint: 'ENOTSUP',
posixAlignment: 'ENOTSUP',
note:
'listen: bareTcp.Server not merged in ctx.bare (bare-tcp bundle).'
}
}
const backlog = Math.min(
511,
Math.max(1, Math.floor(Number(args.backlog) || 511))
)
const acceptQmax = bareOsPosixAcceptQueueMax(shellEnv)
const dgramQmax = bareOsPosixDgramRecvQueueMax(shellEnv)
const server = new TcpServer()
slot.acceptQueue = []
server.on('connection', (sock) => {
if (!Array.isArray(slot.acceptQueue)) return
if (slot.acceptQueue.length >= acceptQmax) {
try {
sock.destroy?.()
} catch (_) {}
return
}
const wrap = {
sock,
tcpRecvQueue: [],
tcpRecvDropped: 0
}
sock.on('data', (message) => {
let u8 =
message instanceof Uint8Array
? message
: b4a.from(message)
if (u8.byteLength > 1024 * 1024)
u8 = u8.slice(0, 1024 * 1024)
if (wrap.tcpRecvQueue.length >= dgramQmax) {
wrap.tcpRecvDropped = (wrap.tcpRecvDropped || 0) + 1
return
}
wrap.tcpRecvQueue.push({ buf: u8.slice() })
})
slot.acceptQueue.push(wrap)
})
try {
await new Promise((resolve, reject) => {
server.once('error', reject)
server.once('listening', resolve)
server.listen(slot.bindPort, slot.bindHost, backlog)
})
} catch (e) {
return {
ok: false,
op: name,
code: 'EADDRINUSE',
errnoHint: 'EADDRINUSE',
posixAlignment: 'partial',
note: String(e && e.message ? e.message : e)
}
}
slot.server = server
slot.state = 'listening'
this.bareOsLogicalFds[k] =
'bare-os-socket-bridge:tcp-listen:' +
slot.bindHost +
':' +
slot.bindPort
const addr =
server.address && typeof server.address === 'function'
? server.address()
: null
return {
ok: true,
op: name,
fd,
bridge: true,
posixAlignment: 'partial',
address: addr
}
}
if (name === 'accept') {
const fd = Number(args.fd)
if (!Number.isFinite(fd)) {
return {
ok: false,
op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'accept: listening fd required'
}
}
const k = String(fd >>> 0)
const slot =
this.bareOsSocketBridgeByFd &&
typeof this.bareOsSocketBridgeByFd === 'object'
? this.bareOsSocketBridgeByFd[k]
: null
if (!slot || slot.state !== 'listening') {
return {
ok: false,
op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'accept: fd must be a listening SOCK_STREAM bridge socket.'
}
}
const nonblock =
(this.bareOsLogicalFdFlags[k] & 0x800) === 0x800
const blockMax = bareOsPosixAcceptBlockMsMax(shellEnv)
const t0 = Date.now()
while (true) {
const q = slot.acceptQueue
if (Array.isArray(q) && q.length > 0) {
const wrap = q.shift()
const sock = wrap && wrap.sock
if (!sock) continue
const st = this.bareOsPosixFdSimState
const newFd = st.nextFd++
const nk = String(newFd)
this.bareOsSocketBridgeByFd[nk] = {
state: 'connected',
sock,
transport: 'tcp',
sockType: 1,
type: 1,
tcpRecvQueue: wrap.tcpRecvQueue,
tcpRecvDropped: wrap.tcpRecvDropped || 0
}
this.bareOsRegisterLogicalFd(
newFd,
'bare-os-socket-bridge:tcp-accepted'
)
return {
ok: true,
op: name,
fd: newFd,
bridge: true,
posixAlignment: 'partial',
listenFd: fd
}
}
if (nonblock) {
return {
ok: false,
op: name,
code: 'EAGAIN',
errnoHint: 'EAGAIN',
posixAlignment: 'EAGAIN',
bridge: true,
note: 'accept: no connection ready (O_NONBLOCK)'
}
}
if (Date.now() - t0 >= blockMax) {
return {
ok: false,
op: name,
code: 'EAGAIN',
errnoHint: 'EAGAIN',
posixAlignment: 'partial',
bridge: true,
note:
'accept: timed out waiting (same budget as BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX)'
}
}
await new Promise((r) => setTimeout(r, 10))
}
}
if (name === 'shutdown') {
const fd = Number(args.fd)
if (!Number.isFinite(fd)) {
return {
ok: false,
op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'shutdown: fd required'
}
}
const k = String(fd >>> 0)
const slot =
this.bareOsSocketBridgeByFd &&
typeof this.bareOsSocketBridgeByFd === 'object'
? this.bareOsSocketBridgeByFd[k]
: null
if (!slot) {
return {
ok: false,
op: name,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'shutdown: not a bridge fd'
}
}
if (slot.state === 'listening' && slot.server) {
try {
slot.server.close?.()
} catch (_) {}
slot.server = null
if (Array.isArray(slot.acceptQueue)) {
for (const w of slot.acceptQueue) {
try {
w.sock?.destroy?.()
} catch (_) {}
}
slot.acceptQueue = []
}
slot.state = 'closed'
delete this.bareOsSocketBridgeByFd[k]
return {
ok: true,
op: name,
bridge: true,
posixAlignment: 'partial'
}
}
if (slot.state === 'connected' && slot.sock) {
try {
slot.sock.destroy?.()
} catch (_) {}
slot.state = 'closed'
delete this.bareOsSocketBridgeByFd[k]
return {
ok: true,
op: name,
bridge: true,
posixAlignment: 'partial'
}
}
return { return {
ok: false, ok: false,
op: name, op: name,
code: 'ENOTSUP', code: 'ENOTSUP',
errnoHint: 'ENOTSUP', errnoHint: 'ENOTSUP',
posixAlignment: 'ENOTSUP', posixAlignment: 'ENOTSUP',
note: note: 'shutdown: bridge fd not connected or listening.'
'Bridge mode implements socket+connect via bareTcp (stream) or bareDgram (UDP); use ctx.bare / Hyperswarm for listen/accept servers.'
} }
} }
if ( if (
@@ -5193,7 +5623,7 @@ async function executeKernel(disk, store, swarm, initSource) {
!slot || !slot ||
slot.state !== 'connected' || slot.state !== 'connected' ||
!slot.sock || !slot.sock ||
slot.transport !== 'udp' (slot.transport !== 'udp' && slot.transport !== 'tcp')
) { ) {
return { return {
ok: false, ok: false,
@@ -5202,12 +5632,184 @@ async function executeKernel(disk, store, swarm, initSource) {
errnoHint: 'ENOTSUP', errnoHint: 'ENOTSUP',
posixAlignment: 'ENOTSUP', posixAlignment: 'ENOTSUP',
note: note:
'Bridge send/sendmsg/recv/recvfrom/recvmsg supported for connected SOCK_DGRAM fds only; use Hyperswarm streams for TCP payload I/O.' 'Bridge send/sendmsg/recv/recvfrom/recvmsg supported for connected SOCK_DGRAM or SOCK_STREAM (accepted) fds.'
}
}
if (slot.transport === 'tcp') {
if (logicalOp === 'send' || logicalOp === 'sendmsg') {
let payload
if (logicalOp === 'sendmsg') {
const anc = bareOsSendmsgAncillaryRejectReason(
args && typeof args === 'object'
? /** @type {Record<string, unknown>} */ (args)
: {}
)
if (anc) {
return {
ok: false,
op: 'sendmsg',
code: 'ENOTSUP',
errnoHint: 'ENOTSUP',
posixAlignment: 'ENOTSUP',
ancillaryReject: anc,
note:
'sendmsg: ancillary control messages not implemented on TCP bridge.'
}
}
const f = bareOsFlattenSendmsgIovs(args)
if (!f.ok) return f.err
payload = f.buf
} else {
payload = args.buf ?? args.buffer ?? args.data
if (payload == null) {
return {
ok: false,
op: logicalOp,
code: 'EINVAL',
errnoHint: 'EINVAL'
}
}
if (typeof payload === 'string')
payload = b4a.from(String(payload), 'utf8')
if (!(payload instanceof Uint8Array)) {
return {
ok: false,
op: logicalOp,
code: 'EINVAL',
errnoHint: 'EINVAL',
note: 'send: buf must be Uint8Array or string'
}
}
}
await new Promise((resolve, reject) => {
try {
const w = slot.sock.write(payload, (err) =>
err ? reject(err) : resolve(undefined)
)
if (w === false) {
slot.sock.once('drain', () => resolve(undefined))
}
} catch (e) {
reject(e)
}
})
return {
ok: true,
op: logicalOp,
fd,
bytesSent: payload.byteLength,
bridge: true,
posixAlignment: 'partial',
transport: 'tcp'
}
}
const maxBuf = Math.max(
1,
Math.min(
Number(args.len ?? args.length ?? args.max ?? 65536) || 65536,
1024 * 1024
)
)
const nonblock =
(this.bareOsLogicalFdFlags[k] & 0x800) === 0x800
const t0 = Date.now()
const blockMax = bareOsPosixAcceptBlockMsMax(shellEnv)
while (true) {
const q = slot.tcpRecvQueue
if (Array.isArray(q) && q.length > 0) {
const row = q.shift()
if (row && row.buf instanceof Uint8Array) {
let out = row.buf
if (out.byteLength > maxBuf) {
const rest = out.slice(maxBuf)
out = out.slice(0, maxBuf)
q.unshift({ buf: rest })
}
const base = {
ok: true,
op: logicalOp,
fd,
bytesReceived: out.byteLength,
buf: out,
bridge: true,
posixAlignment: 'partial',
transport: 'tcp',
tcpRecvDropped: slot.tcpRecvDropped || 0
}
if (
logicalOp === 'recvfrom' ||
logicalOp === 'recvmsg'
) {
base.address = slot.sock.remoteAddress
base.port = slot.sock.remotePort
}
if (logicalOp === 'recvmsg') {
base.msgHdr = {
schema: 1,
name:
slot.sock.remoteAddress != null
? {
address: String(slot.sock.remoteAddress || ''),
port: Number(slot.sock.remotePort) >>> 0
}
: null,
flags: 0,
controllen: 0,
note:
'TCP bridge: single flat buffer; ancillary ENOTSUP-shaped.'
}
}
return base
}
}
if (nonblock) {
return {
ok: false,
op: logicalOp,
code: 'EAGAIN',
errnoHint: 'EAGAIN',
posixAlignment: 'EAGAIN',
bridge: true,
note: 'recv: no data ready (O_NONBLOCK)',
tcpRecvDropped: slot.tcpRecvDropped || 0
}
}
if (Date.now() - t0 >= blockMax) {
return {
ok: false,
op: logicalOp,
code: 'EAGAIN',
errnoHint: 'EAGAIN',
posixAlignment: 'partial',
bridge: true,
note:
'recv: timed out waiting for TCP segment (BARE_OS_POSIX_DGRAM_RECV_BLOCK_MS_MAX budget)',
tcpRecvDropped: slot.tcpRecvDropped || 0
}
}
await new Promise((r) => setTimeout(r, 10))
} }
} }
if (logicalOp === 'send' || logicalOp === 'sendmsg') { if (logicalOp === 'send' || logicalOp === 'sendmsg') {
let payload let payload
if (logicalOp === 'sendmsg') { if (logicalOp === 'sendmsg') {
const anc = bareOsSendmsgAncillaryRejectReason(
args && typeof args === 'object'
? /** @type {Record<string, unknown>} */ (args)
: {}
)
if (anc) {
return {
ok: false,
op: 'sendmsg',
code: 'ENOTSUP',
errnoHint: 'ENOTSUP',
posixAlignment: 'ENOTSUP',
ancillaryReject: anc,
note:
'sendmsg: ancillary control messages (cmsgs/control/controllen/msgHdr.*) are not implemented on the socket FD bridge; use payload-only send or bare IPC.'
}
}
const f = bareOsFlattenSendmsgIovs(args) const f = bareOsFlattenSendmsgIovs(args)
if (!f.ok) return f.err if (!f.ok) return f.err
payload = f.buf payload = f.buf
@@ -5529,6 +6131,19 @@ async function executeKernel(disk, store, swarm, initSource) {
h && typeof h === 'object' && !Array.isArray(h) ? { ...h } : { schema: 1 } h && typeof h === 'object' && !Array.isArray(h) ? { ...h } : { schema: 1 }
o.atMs = Date.now() o.atMs = Date.now()
if (handles.length) o.snapshot_handles = handles if (handles.length) o.snapshot_handles = handles
const wfRaw = String(
shellEnv.BARE_OS_CORESTORE_SNAPSHOT_WORKFLOW_JSON || ''
).trim()
if (wfRaw) {
try {
const w = JSON.parse(wfRaw)
if (w && typeof w === 'object' && !Array.isArray(w)) {
o.corestoreSnapshotWorkflow = w
}
} catch {
o.corestoreSnapshotWorkflowParseError = true
}
}
return o return o
}, },
/** /**
@@ -6582,19 +7197,20 @@ async function executeKernel(disk, store, swarm, initSource) {
} }
}, },
bareOsHrpcAllowlistProbe() { bareOsHrpcAllowlistProbe() {
const raw = String(shellEnv.BARE_OS_HRPC_ALLOWLIST_JSON || '').trim() const parsed = parseBareOsHrpcAllowlistJson(
if (raw) { String(shellEnv.BARE_OS_HRPC_ALLOWLIST_JSON || '')
try { )
return { if (parsed.parseError) {
ok: true, return {
source: 'env', ok: false,
allowlist: JSON.parse(raw) note: 'invalid BARE_OS_HRPC_ALLOWLIST_JSON'
} }
} catch { }
return { if (parsed.allow && parsed.allow.size > 0) {
ok: false, return {
note: 'invalid BARE_OS_HRPC_ALLOWLIST_JSON' ok: true,
} source: 'env',
allowlist: [...parsed.allow].sort()
} }
} }
return { return {
@@ -2,4 +2,4 @@
* Semantic version of the booter `ctx` contract for custom kernels. * Semantic version of the booter `ctx` contract for custom kernels.
* Bump when adding/removing/renaming documented `ctx` fields or changing behavior. * Bump when adding/removing/renaming documented `ctx` fields or changing behavior.
*/ */
export const BARE_OS_CTX_API_VERSION = '1.44.0' export const BARE_OS_CTX_API_VERSION = '1.45.0'
@@ -0,0 +1,39 @@
/**
* Parse optional **`BARE_OS_HRPC_ALLOWLIST_JSON`** for stock **`ctx.bareOsHrpcRequest`**.
* @param {string} raw
* @returns {{ allow: Set<string> | null, parseError: boolean }}
*/
export function parseBareOsHrpcAllowlistJson(raw) {
const s = String(raw || '').trim()
if (!s) return { allow: null, parseError: false }
try {
const parsed = JSON.parse(s)
/** @type {Set<string>} */
const allow = new Set()
if (Array.isArray(parsed)) {
for (const v of parsed) {
const x = String(v || '').trim()
if (x) allow.add(x)
}
} else if (parsed && typeof parsed === 'object') {
for (const [k, v] of Object.entries(parsed)) {
if (v) allow.add(String(k).trim())
}
}
return { allow: allow.size > 0 ? allow : null, parseError: false }
} catch {
return { allow: null, parseError: true }
}
}
/**
* @param {Set<string> | null} allow
* @param {string} svc
* @param {string} method
* @returns {boolean} true when the route is denied by a non-empty allowlist
*/
export function bareOsHrpcAllowlistDeniesRoute(allow, svc, method) {
if (!allow || allow.size === 0) return false
const key = `${svc}.${method}`
return !allow.has('*') && !allow.has(`${svc}.*`) && !allow.has(key)
}
@@ -28,9 +28,14 @@ export function buildBareOsPearInspectLoggerTlsProcJson(id, env, runtimeHints) {
switch (id) { switch (id) {
case 'pear_doctor_state': case 'pear_doctor_state':
return { return {
schema: 1, schema: 2,
state: parseJsonEnv('BARE_OS_PEAR_DOCTOR_STATE_JSON'), state: parseJsonEnv('BARE_OS_PEAR_DOCTOR_STATE_JSON'),
note: 'pear-doctor operator health sketch.', runtimeVersion: esc('BARE_OS_PEAR_RUNTIME_VERSION') || undefined,
pearInspectProbe:
esc('BARE_OS_PEAR_INSPECT_PROBE') === '1' ||
esc('BARE_OS_PEAR_INSPECT_PROBE') === 'true',
pearDoctorModuleHint: esc('BARE_OS_PEAR_DOCTOR_MODULE') || undefined,
note: 'pear-doctor + pear-runtime parity (schema 2): merge env with pear-inspect / pear-runtime-updater host wiring.',
atMs: now atMs: now
} }
case 'pear_workshop_flags': case 'pear_workshop_flags':
@@ -350,25 +350,34 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
name: 'bind', name: 'bind',
category: 'ipc', category: 'ipc',
stability: 'experimental', stability: 'experimental',
posixAlignment: 'ENOTSUP', posixAlignment: 'partial',
mapsTo: ['ctx.bareOsSyscall("bind")', 'ENOSYS-shaped probe'], mapsTo: [
errnoHint: 'ENOSYS' 'ctx.bareOsSyscall("bind")',
'SOCK_STREAM bridge: port+host before listen (SOCK_DGRAM bind ENOTSUP)'
],
errnoHint: 'EINVAL'
}, },
{ {
name: 'listen', name: 'listen',
category: 'ipc', category: 'ipc',
stability: 'experimental', stability: 'experimental',
posixAlignment: 'ENOTSUP', posixAlignment: 'partial',
mapsTo: ['ctx.bareOsSyscall("listen")', 'ENOSYS-shaped probe'], mapsTo: [
errnoHint: 'ENOSYS' 'ctx.bareOsSyscall("listen")',
'bareTcp.Server.listen when BARE_OS_POSIX_SOCKET_FD_BRIDGE'
],
errnoHint: 'EADDRINUSE'
}, },
{ {
name: 'accept', name: 'accept',
category: 'ipc', category: 'ipc',
stability: 'experimental', stability: 'experimental',
posixAlignment: 'ENOTSUP', posixAlignment: 'partial',
mapsTo: ['ctx.bareOsSyscall("accept")', 'ENOSYS-shaped probe'], mapsTo: [
errnoHint: 'ENOSYS' 'ctx.bareOsSyscall("accept")',
'dequeue accepted TCP socket to new logical fd; EAGAIN when empty + O_NONBLOCK'
],
errnoHint: 'EAGAIN'
}, },
{ {
name: 'connect', name: 'connect',
@@ -382,18 +391,21 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
name: 'send', name: 'send',
category: 'ipc', category: 'ipc',
stability: 'experimental', stability: 'experimental',
posixAlignment: 'ENOTSUP', posixAlignment: 'partial',
mapsTo: ['ctx.bareOsSyscall("send")', 'ENOSYS-shaped probe'], mapsTo: [
'ctx.bareOsSyscall("send")',
'SOCK_DGRAM + SOCK_STREAM (accepted) bridge write'
],
errnoHint: 'ENOSYS' errnoHint: 'ENOSYS'
}, },
{ {
name: 'recv', name: 'recv',
category: 'ipc', category: 'ipc',
stability: 'experimental', stability: 'experimental',
posixAlignment: 'ENOTSUP', posixAlignment: 'partial',
mapsTo: [ mapsTo: [
'ctx.bareOsSyscall("recv")', 'ctx.bareOsSyscall("recv")',
'SOCK_DGRAM bridge dequeue (BARE_OS_POSIX_SOCKET_FD_BRIDGE)' 'SOCK_DGRAM bridge dequeue; SOCK_STREAM accepted fd tcpRecvQueue (BARE_OS_POSIX_SOCKET_FD_BRIDGE)'
], ],
errnoHint: 'ENOSYS' errnoHint: 'ENOSYS'
}, },
@@ -401,10 +413,10 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
name: 'recvfrom', name: 'recvfrom',
category: 'ipc', category: 'ipc',
stability: 'experimental', stability: 'experimental',
posixAlignment: 'ENOTSUP', posixAlignment: 'partial',
mapsTo: [ mapsTo: [
'ctx.bareOsSyscall("recvfrom")', 'ctx.bareOsSyscall("recvfrom")',
'SOCK_DGRAM bridge + peer address fields when available' 'SOCK_DGRAM bridge + peer address; SOCK_STREAM accepted + remoteAddress/remotePort'
], ],
errnoHint: 'ENOSYS' errnoHint: 'ENOSYS'
}, },
@@ -415,7 +427,7 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
posixAlignment: 'partial', posixAlignment: 'partial',
mapsTo: [ mapsTo: [
'ctx.bareOsSyscall("sendmsg")', 'ctx.bareOsSyscall("sendmsg")',
'SOCK_DGRAM bridge flattened iovs (BARE_OS_POSIX_SOCKET_FD_BRIDGE); ancillary CMSGS ENOTSUP' 'SOCK_DGRAM + SOCK_STREAM bridge flattened iovs (BARE_OS_POSIX_SOCKET_FD_BRIDGE); ancillary CMSGS ENOTSUP'
], ],
errnoHint: 'ENOSYS' errnoHint: 'ENOSYS'
}, },
@@ -426,7 +438,7 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
posixAlignment: 'partial', posixAlignment: 'partial',
mapsTo: [ mapsTo: [
'ctx.bareOsSyscall("recvmsg")', 'ctx.bareOsSyscall("recvmsg")',
'SOCK_DGRAM bridge + msgHdr.name from rinfo; scatter iov / SCM_RIGHTS ENOTSUP' 'SOCK_DGRAM bridge + msgHdr.name from rinfo; SOCK_STREAM accepted + remote addr; scatter iov / SCM_RIGHTS ENOTSUP'
], ],
errnoHint: 'ENOSYS' errnoHint: 'ENOSYS'
}, },
@@ -434,9 +446,12 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
name: 'shutdown', name: 'shutdown',
category: 'ipc', category: 'ipc',
stability: 'experimental', stability: 'experimental',
posixAlignment: 'ENOTSUP', posixAlignment: 'partial',
mapsTo: ['ctx.bareOsSyscall("shutdown")', 'ENOSYS-shaped probe'], mapsTo: [
errnoHint: 'ENOSYS' 'ctx.bareOsSyscall("shutdown")',
'TCP bridge: destroy socket or close listening Server'
],
errnoHint: 'EINVAL'
} }
]) ])
@@ -33,16 +33,29 @@ export function buildBareOsSyscallsProcJson(p) {
namesCsv: bareOsPosixXshOpsCsv() namesCsv: bareOsPosixXshOpsCsv()
}, },
socketMsgSurface: { socketMsgSurface: {
schema: 2, schema: 3,
ancillaryControl: {
supported: false,
errno: 'ENOTSUP',
rejectKeys: [
'cmsgs',
'control',
'controllen',
'msgHdr.control',
'msgHdr.cmsgs'
],
note:
'Booter returns ENOTSUP before send when non-empty ancillary fields are present; recvmsg always reports controllen 0.'
},
sendmsg: { sendmsg: {
bridgePartial: true, bridgePartial: true,
defaultErrno: 'ENOTSUP', defaultErrno: 'ENOTSUP',
note: 'With BARE_OS_POSIX_SOCKET_FD_BRIDGE and SOCK_DGRAM, sendmsg flattens bounded iovs into one datagram; flags and ancillary CMSGS remain ENOTSUP.' note: 'With BARE_OS_POSIX_SOCKET_FD_BRIDGE and SOCK_DGRAM, sendmsg flattens bounded iovs into one datagram; non-empty ancillary CMSGS rejected with ENOTSUP + ancillaryReject (schema 3).'
}, },
recvmsg: { recvmsg: {
bridgePartial: true, bridgePartial: true,
defaultErrno: 'ENOTSUP', defaultErrno: 'ENOTSUP',
note: 'With bridge + SOCK_DGRAM, recvmsg returns buf + msgHdr.name from rinfo; SCM_RIGHTS / scatter iov ENOTSUP.' note: 'With bridge + SOCK_DGRAM, recvmsg returns buf + msgHdr.name from rinfo; SCM_RIGHTS / scatter iov / ancillary recv ENOTSUP-shaped (controllen 0).'
} }
}, },
errnoHints: bareOsErrnoTableForProc(), errnoHints: bareOsErrnoTableForProc(),
@@ -101,6 +114,7 @@ export function buildBareOsSyscallsProcJson(p) {
'F_SETLKW', 'F_SETLKW',
'cooperative advisory locks per absolute path (or fd→path); session-scoped', 'cooperative advisory locks per absolute path (or fd→path); session-scoped',
'optional F_SETLKW blocking wait when BARE_OS_POSIX_FCNTL_BLOCKING_WAIT (cap BARE_OS_FCNTL_LOCK_WAIT_MS_MAX)', 'optional F_SETLKW blocking wait when BARE_OS_POSIX_FCNTL_BLOCKING_WAIT (cap BARE_OS_FCNTL_LOCK_WAIT_MS_MAX)',
'waiters wake FIFO on unlock; no host deadlock detection; starvation possible under heavy writer churn',
'O_APPEND 0x400', 'O_APPEND 0x400',
'O_NONBLOCK 0x800', 'O_NONBLOCK 0x800',
'bareOsLogicalFdFlags per fd string key' 'bareOsLogicalFdFlags per fd string key'
@@ -118,7 +132,7 @@ export function buildBareOsSyscallsProcJson(p) {
socketFamily: { socketFamily: {
mapsTo: [ mapsTo: [
'ctx.bareOsSyscall("socket"|"bind"|"listen"|"accept"|"connect"|"send"|"recv"|"recvfrom"|"shutdown")', 'ctx.bareOsSyscall("socket"|"bind"|"listen"|"accept"|"connect"|"send"|"recv"|"recvfrom"|"shutdown")',
'BARE_OS_POSIX_SOCKET_FD_BRIDGE=1: SOCK_STREAM+connect via bareTcp; SOCK_DGRAM+connect+send+recv+recvfrom via bareDgram (UDX) with bounded recv queue; bind/listen/accept ENOTSUP-shaped in bridge' 'BARE_OS_POSIX_SOCKET_FD_BRIDGE=1: SOCK_STREAM connect via bareTcp.Socket; passive SOCK_STREAM bind+listen+accept via bareTcp.Server (accepted fds use TCP recv queue + poll/select); SOCK_DGRAM connect+send+recv+recvfrom via bareDgram (UDX); BARE_OS_POSIX_ACCEPT_QUEUE_MAX caps pending accepts'
], ],
notKernelSockets: true notKernelSockets: true
} }
@@ -224,8 +224,25 @@ export async function registerIdentity(ctx, passphrase) {
*/ */
export async function unlockIdentity(ctx, passphrase) { export async function unlockIdentity(ctx, passphrase) {
const buf = await ctx.personalDrive.get(ACCOUNT_PATH) const buf = await ctx.personalDrive.get(ACCOUNT_PATH)
if (!buf) throw new Error('No account — use: login --new <passphrase>') if (!buf) {
const { publicKey, secretKey } = decodeAccount(passphrase, b4a.from(buf)) const e = new Error('No account — use: login --new <passphrase>')
/** @type {Error & { code?: string }} */ (e).code =
'BARE_OS_IDENTITY_NO_ACCOUNT'
throw e
}
let publicKey
let secretKey
try {
;({ publicKey, secretKey } = decodeAccount(passphrase, b4a.from(buf)))
} catch (err) {
const e = new Error(
'Passphrase does not unlock this account (wrong passphrase or unreadable account file).'
)
const ee = /** @type {Error & { code?: string, cause?: unknown }} */ (e)
ee.code = 'BARE_OS_IDENTITY_PASSPHRASE_REJECTED'
ee.cause = err
throw e
}
wipeSecret(ctx) wipeSecret(ctx)
await applyUnlockedEnv(ctx, publicKey, secretKey) await applyUnlockedEnv(ctx, publicKey, secretKey)
await ensureBareDir(ctx) await ensureBareDir(ctx)
+23 -6
View File
@@ -1114,6 +1114,12 @@ async function execParsedPipeline(ctx, pipeline) {
let stdinText = typeof ctx.shellStdin === 'string' ? ctx.shellStdin : null let stdinText = typeof ctx.shellStdin === 'string' ? ctx.shellStdin : null
/** Last completed pipeline stage exit (POSIX default: status of last stage; optional pipefail). */ /** Last completed pipeline stage exit (POSIX default: status of last stage; optional pipefail). */
let pipelineLastExit = 0 let pipelineLastExit = 0
/** True when **`BARE_OS_SHELL_PIPEFAIL`** is already set or set by a stage prefix in this pipeline. */
let pipelineWantsPipefail =
env.BARE_OS_SHELL_PIPEFAIL === '1' ||
env.BARE_OS_SHELL_PIPEFAIL === 'true'
/** First non-zero stage exit when pipefail is active (handbook: first failing stage wins). */
let pipefailFirstNonZero = 0
try { try {
for (let pi = 0; pi < pipeline.length; pi++) { for (let pi = 0; pi < pipeline.length; pi++) {
@@ -1267,6 +1273,12 @@ async function execParsedPipeline(ctx, pipeline) {
} }
env[k] = expandWord(val, env) env[k] = expandWord(val, env)
} }
if (
env.BARE_OS_SHELL_PIPEFAIL === '1' ||
env.BARE_OS_SHELL_PIPEFAIL === 'true'
) {
pipelineWantsPipefail = true
}
if (!cmd.argv.length) { if (!cmd.argv.length) {
ctx.exitCode = 0 ctx.exitCode = 0
@@ -1701,11 +1713,12 @@ async function execParsedPipeline(ctx, pipeline) {
} }
pipelineLastExit = Number(ctx.exitCode) || 0 pipelineLastExit = Number(ctx.exitCode) || 0
const pipefail = if (
env.BARE_OS_SHELL_PIPEFAIL === '1' || pipelineWantsPipefail &&
env.BARE_OS_SHELL_PIPEFAIL === 'true' pipefailFirstNonZero === 0 &&
if (pipefail && pipelineLastExit !== 0) { pipelineLastExit !== 0
return 'ok' ) {
pipefailFirstNonZero = pipelineLastExit
} }
if (ctx.bareOsPipelineStageError) { if (ctx.bareOsPipelineStageError) {
delete ctx.bareOsPipelineStageError delete ctx.bareOsPipelineStageError
@@ -1716,7 +1729,11 @@ async function execParsedPipeline(ctx, pipeline) {
ctx.shellStdin = stdinText ?? undefined ctx.shellStdin = stdinText ?? undefined
} }
ctx.exitCode = pipelineLastExit ctx.exitCode = pipelineWantsPipefail
? pipefailFirstNonZero !== 0
? pipefailFirstNonZero
: pipelineLastExit
: pipelineLastExit
return 'ok' return 'ok'
} catch (e) { } catch (e) {
ctx.console.error((e && e.message) || String(e)) ctx.console.error((e && e.message) || String(e))
+79
View File
@@ -92,6 +92,10 @@ import {
import { parseUnitDropInText } from './lib/bare-initd-user.js' import { parseUnitDropInText } from './lib/bare-initd-user.js'
import { bareOsProcessTableSnapshot } from './lib/bare-os-process-table.js' import { bareOsProcessTableSnapshot } from './lib/bare-os-process-table.js'
import { buildBareOsSyscallsProcJson } from './lib/bare-os-syscalls-proc-json.js' import { buildBareOsSyscallsProcJson } from './lib/bare-os-syscalls-proc-json.js'
import {
parseBareOsHrpcAllowlistJson,
bareOsHrpcAllowlistDeniesRoute
} from './lib/bare-os-hrpc-allowlist.js'
import { buildBareOsProtomuxExtensionsProcJson } from './lib/bare-os-protomux-extensions-proc.js' import { buildBareOsProtomuxExtensionsProcJson } from './lib/bare-os-protomux-extensions-proc.js'
import { createBareOsDiskOsBridge } from './lib/bare-os-disk-os-bridge.js' import { createBareOsDiskOsBridge } from './lib/bare-os-disk-os-bridge.js'
import { buildBareOsReplicationLiveSketch } from './lib/bare-os-replication-proc-live.js' import { buildBareOsReplicationLiveSketch } from './lib/bare-os-replication-proc-live.js'
@@ -1329,10 +1333,75 @@ test('buildBareOsSyscallsProcJson exposes posixLike fd mapping', async (t) => {
t.ok(j.posixXsh.namesCsv.includes('sendmsg')) t.ok(j.posixXsh.namesCsv.includes('sendmsg'))
t.ok(j.posixXsh.namesCsv.includes('recvmsg')) t.ok(j.posixXsh.namesCsv.includes('recvmsg'))
t.ok(j.posixXsh.namesCsv.includes('shutdown')) t.ok(j.posixXsh.namesCsv.includes('shutdown'))
t.is(j.socketMsgSurface?.schema, 3)
t.is(j.socketMsgSurface?.ancillaryControl?.supported, false)
t.is(j.socketMsgSurface?.ancillaryControl?.errno, 'ENOTSUP')
t.ok(Array.isArray(j.socketMsgSurface?.ancillaryControl?.rejectKeys))
const xsh = j.opsDetail.filter((r) => r.posixAlignment) const xsh = j.opsDetail.filter((r) => r.posixAlignment)
t.ok(xsh.length >= 10) t.ok(xsh.length >= 10)
}) })
test('parseBareOsHrpcAllowlistJson + bareOsHrpcAllowlistDeniesRoute', async (t) => {
t.is(parseBareOsHrpcAllowlistJson('').allow, null)
t.is(parseBareOsHrpcAllowlistJson(' ').allow, null)
const a1 = parseBareOsHrpcAllowlistJson('["kernel.ping"]')
t.ok(a1.allow && a1.allow.has('kernel.ping'))
t.ok(bareOsHrpcAllowlistDeniesRoute(a1.allow, 'kernel', 'capabilities'))
t.absent(bareOsHrpcAllowlistDeniesRoute(a1.allow, 'kernel', 'ping'))
const a2 = parseBareOsHrpcAllowlistJson('{"kernel.ping":true}')
t.ok(a2.allow && a2.allow.has('kernel.ping'))
const a3 = parseBareOsHrpcAllowlistJson('{"*":true}')
t.ok(a3.allow && a3.allow.has('*'))
t.absent(bareOsHrpcAllowlistDeniesRoute(a3.allow, 'vfs', 'readText'))
const a4 = parseBareOsHrpcAllowlistJson('{"kernel.*":true}')
t.absent(bareOsHrpcAllowlistDeniesRoute(a4.allow, 'kernel', 'capabilities'))
t.ok(bareOsHrpcAllowlistDeniesRoute(a4.allow, 'vfs', 'readText'))
t.ok(parseBareOsHrpcAllowlistJson('{').parseError)
})
test('pear_doctor_state proc JSON schema 2 parity fields', async (t) => {
const j = buildBareOsPearInspectLoggerTlsProcJson(
'pear_doctor_state',
{
BARE_OS_PEAR_DOCTOR_STATE_JSON: '{"ok":true}',
BARE_OS_PEAR_RUNTIME_VERSION: '1.2.3',
BARE_OS_PEAR_INSPECT_PROBE: '1',
BARE_OS_PEAR_DOCTOR_MODULE: 'pear-doctor'
},
{}
)
t.is(j.schema, 2)
t.is(j.runtimeVersion, '1.2.3')
t.is(j.pearInspectProbe, true)
t.is(j.pearDoctorModuleHint, 'pear-doctor')
t.ok(j.state && typeof j.state === 'object')
})
test('split suffix rolls past zz into three-letter names', async (t) => {
const a = 'abcdefghijklmnopqrstuvwxyz'
function suffix(i) {
let idx = i
let len = 2
let span = 26 ** len
while (idx >= span) {
idx -= span
len++
span = 26 ** len
}
let s = ''
let n = idx
for (let p = 0; p < len; p++) {
s = a[n % 26] + s
n = Math.floor(n / 26)
}
return 'x' + s
}
t.is(suffix(0), 'xaa')
t.is(suffix(675), 'xzz')
t.is(suffix(676), 'xaaa')
t.is(suffix(677), 'xaab')
})
test('disk.os replication_snapshot and replication_operator_sketch RPCs', async (t) => { test('disk.os replication_snapshot and replication_operator_sketch RPCs', async (t) => {
const dir = testCorestoreDir('diskosrpc') const dir = testCorestoreDir('diskosrpc')
const store = new Corestore(dir) const store = new Corestore(dir)
@@ -3250,6 +3319,16 @@ async function run(ctx, argv) {
t.is(ran.join(','), 'false,last', 'pipeline runs both stages') t.is(ran.join(','), 'false,last', 'pipeline runs both stages')
t.is(ctx.exitCode, 0, 'POSIX-like: pipeline exit status is last stage') t.is(ctx.exitCode, 0, 'POSIX-like: pipeline exit status is last stage')
ran.length = 0
ctx.exitCode = 0
await execShellLine(ctx, 'BARE_OS_SHELL_PIPEFAIL=1 false | last')
t.is(ran.join(','), 'false,last')
t.is(
ctx.exitCode,
1,
'pipefail: failure in an earlier stage overrides last stage success'
)
await store.close() await store.close()
rmSync(dir, { recursive: true, force: true }) rmSync(dir, { recursive: true, force: true })
}) })
+32 -2
View File
@@ -1,12 +1,34 @@
/** /**
* Move/rename via copy + delete. Hyperdrive has no single-key rename across paths, so * Move/rename via copy + delete. Hyperdrive has no single-key rename across paths, so
* directory trees and cross-location moves are duplicated then removed. A single regular * directory trees and cross-location moves are duplicated then removed. A single regular
* file to a new non-directory path uses read + write + unlink when detected below. * file to a new non-directory path uses a two-phase write: staging buffer bytes under a
* unique **`.bare-os-mv-tmp.*`** name in the **resolved destination directory**, writing the final name,
* removing the staging file, then unlinking the source so a failed final write leaves
* the source path intact (staging is best-effort removed).
* *
* Documented limitations: cross-volume moves always copy+delete; EXDEV-style behavior is * Documented limitations: cross-volume moves always copy+delete; EXDEV-style behavior is
* implicit. Busy targets, partial copy failures, and union read-only trees surface as * implicit. Busy targets, partial copy failures, and union read-only trees surface as
* generic errors from the VFS. Prefer same-directory renames for smallest blast radius. * generic errors from the VFS. Prefer same-directory renames for smallest blast radius.
*/ */
function mvStagingPathForTarget(ctx, target) {
const raw =
ctx.vfs && typeof ctx.vfs.resolveLogical === 'function'
? ctx.vfs.resolveLogical(target)
: String(target || '')
const trimmed = String(raw || '').replace(/\/+$/, '') || '/'
const last = trimmed.lastIndexOf('/')
const dir =
last < 0 ? '/' : last === 0 ? '/' : trimmed.slice(0, last) || '/'
const base =
last < 0 ? trimmed : trimmed.slice(last + 1) || 'file'
const tag =
Date.now().toString(36) +
'-' +
Math.random().toString(36).slice(2, 10) +
Math.random().toString(36).slice(2, 6)
const name = '.bare-os-mv-tmp.' + tag + '.' + base
return dir === '/' ? '/' + name : dir + '/' + name
}
async function mvCopyPath(ctx, from, to, recursive, followSymlink) { async function mvCopyPath(ctx, from, to, recursive, followSymlink) {
const st = await ctx.vfs.lstat(from) const st = await ctx.vfs.lstat(from)
if (!st) return false if (!st) return false
@@ -117,7 +139,15 @@ async function run(ctx, argv) {
if (singleFileToFile) { if (singleFileToFile) {
const buf = await ctx.vfs.readFile(src) const buf = await ctx.vfs.readFile(src)
if (!buf) throw new Error('cannot read source') if (!buf) throw new Error('cannot read source')
await ctx.vfs.writeFile(target, buf) const stage = mvStagingPathForTarget(ctx, target)
await ctx.vfs.writeFile(stage, buf)
try {
await ctx.vfs.writeFile(target, buf)
} catch (e) {
await ctx.vfs.unlink(stage).catch(() => {})
throw e
}
await ctx.vfs.unlink(stage).catch(() => {})
await ctx.vfs.unlink(src) await ctx.vfs.unlink(src)
continue continue
} }
+20 -3
View File
@@ -1,8 +1,25 @@
/**
* POSIX-style suffix: `aa``zz` (676 files), then `aaa`, `aab`, as needed.
* @param {string} prefix
* @param {number} i 0-based output index
*/
function splitSuffix(prefix, i) { function splitSuffix(prefix, i) {
const a = 'abcdefghijklmnopqrstuvwxyz' const a = 'abcdefghijklmnopqrstuvwxyz'
const hi = Math.floor(i / 26) % 26 let idx = i
const lo = i % 26 let len = 2
return prefix + a[hi] + a[lo] let span = 26 ** len
while (idx >= span) {
idx -= span
len++
span = 26 ** len
}
let s = ''
let n = idx
for (let p = 0; p < len; p++) {
s = a[n % 26] + s
n = Math.floor(n / 26)
}
return prefix + s
} }
async function run(ctx, argv) { async function run(ctx, argv) {
+5 -2
View File
@@ -1,9 +1,12 @@
/** /**
* Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host spawn). * Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host fork of arbitrary binaries).
* Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation, * Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation,
* 64 invocations per run. Exceeding limits is a fatal error (exit 125). * 64 invocations per run. Exceeding limits is a fatal error (exit 125).
* Supports -0/--null, -n, -L (lines per invocation; mutually exclusive with -n), -I repl (replace repl in utility argv; implies -n 1 unless -n given). * Supports -0/--null, -n, -L (lines per invocation; mutually exclusive with -n), -I repl (replace repl in utility argv; implies -n 1 unless -n given).
* -P N runs up to N batches in parallel (each batch uses a shallow ctx clone so exitCode does not race). * -P N runs up to N batches in parallel (each batch uses a shallow ctx clone so exitCode does not race); parallelism is still in-process
* over runBinCommand unless the booter/worker stack offloads specific /bin basenames (see BARE_OS_BIN_WORKER_*).
* For explicit host subprocess offload of whitelisted utilities, use ctx.bareOsTrySpawnHostSubprocess from custom scripts with
* BARE_OS_BIN_WORKER_ALLOW / delegate policy not automatic from xargs.
* Max -P is min(requested, BARE_OS_XARGS_MAX_PROCS env, 32); default cap 8 when env unset. * Max -P is min(requested, BARE_OS_XARGS_MAX_PROCS env, 32); default cap 8 when env unset.
*/ */
+2 -1
View File
@@ -5,7 +5,8 @@ Cross-package **version alignment** (ctx API, feature-bits doc, lifecycle schema
## Documentation (rolling) ## Documentation (rolling)
- **Seed RPC** — [`lib/channel.js`](lib/channel.js) rejects unknown **`bare_os.*`** method short names against **`BARE_OS_SEED_RPC_METHOD_SHORT_NAME_SET`** (**`bare_os.rpc_unknown_method`**); boot policy / env may add **`denySeedRpcMethods`** denials on the booter path. See [`docs/architecture/KERNEL_CONTRACT.md`](../../docs/architecture/KERNEL_CONTRACT.md). - **Seed RPC** — [`lib/channel.js`](lib/channel.js) rejects unknown **`bare_os.*`** method short names against **`BARE_OS_SEED_RPC_METHOD_SHORT_NAME_SET`** (**`bare_os.rpc_unknown_method`**); boot policy / env may add **`denySeedRpcMethods`** denials on the booter path. See [`docs/architecture/KERNEL_CONTRACT.md`](../../docs/architecture/KERNEL_CONTRACT.md).
- **Stock hrpc routes** — Documented in **`KERNEL_CONTRACT`**: **`kernel.ping`**, **`kernel.capabilities`**, **`vfs.readText`**, **`bare_os.echo`**, **`bare_os.disk_os_hints`** (validated **`service` / `method` / `payload`**; optional **`BARE_OS_HRPC_ALLOWLIST_JSON`**). - **Stock hrpc routes** — Documented in **`KERNEL_CONTRACT`**: **`kernel.ping`**, **`kernel.capabilities`**, **`vfs.readText`**, **`bare_os.echo`**, **`bare_os.disk_os_hints`** (validated **`service` / `method` / `payload`**; optional **`BARE_OS_HRPC_ALLOWLIST_JSON`** per [`docs/schemas/bare-os-hrpc-allowlist.schema.json`](../../docs/schemas/bare-os-hrpc-allowlist.schema.json); deny-by-default for non-stock routes unless the host replaces **`ctx.bareOsHrpcRequest`** or enables **`BARE_OS_HRPC_EMIT_UNLISTED`**).
- **Wire stack pins** — Booter **`protomux`** / **`hyperswarm`** resolved versions are recorded in [`packages/bare-os-booter/fixtures/protomux-hyperswarm-lock.json`](../packages/bare-os-booter/fixtures/protomux-hyperswarm-lock.json); bump with intentional dependency upgrades and full **`npm test`**.
## 0.9.0 ## 0.9.0
+32 -2
View File
@@ -90,12 +90,34 @@ function bareOsEmitRaw(ctx, chunk) {
/** /**
* Move/rename via copy + delete. Hyperdrive has no single-key rename across paths, so * Move/rename via copy + delete. Hyperdrive has no single-key rename across paths, so
* directory trees and cross-location moves are duplicated then removed. A single regular * directory trees and cross-location moves are duplicated then removed. A single regular
* file to a new non-directory path uses read + write + unlink when detected below. * file to a new non-directory path uses a two-phase write: staging buffer bytes under a
* unique **`.bare-os-mv-tmp.*`** name in the **resolved destination directory**, writing the final name,
* removing the staging file, then unlinking the source — so a failed final write leaves
* the source path intact (staging is best-effort removed).
* *
* Documented limitations: cross-volume moves always copy+delete; EXDEV-style behavior is * Documented limitations: cross-volume moves always copy+delete; EXDEV-style behavior is
* implicit. Busy targets, partial copy failures, and union read-only trees surface as * implicit. Busy targets, partial copy failures, and union read-only trees surface as
* generic errors from the VFS. Prefer same-directory renames for smallest blast radius. * generic errors from the VFS. Prefer same-directory renames for smallest blast radius.
*/ */
function mvStagingPathForTarget(ctx, target) {
const raw =
ctx.vfs && typeof ctx.vfs.resolveLogical === 'function'
? ctx.vfs.resolveLogical(target)
: String(target || '')
const trimmed = String(raw || '').replace(/\/+$/, '') || '/'
const last = trimmed.lastIndexOf('/')
const dir =
last < 0 ? '/' : last === 0 ? '/' : trimmed.slice(0, last) || '/'
const base =
last < 0 ? trimmed : trimmed.slice(last + 1) || 'file'
const tag =
Date.now().toString(36) +
'-' +
Math.random().toString(36).slice(2, 10) +
Math.random().toString(36).slice(2, 6)
const name = '.bare-os-mv-tmp.' + tag + '.' + base
return dir === '/' ? '/' + name : dir + '/' + name
}
async function mvCopyPath(ctx, from, to, recursive, followSymlink) { async function mvCopyPath(ctx, from, to, recursive, followSymlink) {
const st = await ctx.vfs.lstat(from) const st = await ctx.vfs.lstat(from)
if (!st) return false if (!st) return false
@@ -206,7 +228,15 @@ async function run(ctx, argv) {
if (singleFileToFile) { if (singleFileToFile) {
const buf = await ctx.vfs.readFile(src) const buf = await ctx.vfs.readFile(src)
if (!buf) throw new Error('cannot read source') if (!buf) throw new Error('cannot read source')
await ctx.vfs.writeFile(target, buf) const stage = mvStagingPathForTarget(ctx, target)
await ctx.vfs.writeFile(stage, buf)
try {
await ctx.vfs.writeFile(target, buf)
} catch (e) {
await ctx.vfs.unlink(stage).catch(() => {})
throw e
}
await ctx.vfs.unlink(stage).catch(() => {})
await ctx.vfs.unlink(src) await ctx.vfs.unlink(src)
continue continue
} }
+20 -3
View File
@@ -87,11 +87,28 @@ function bareOsEmitRaw(ctx, chunk) {
return false return false
} }
/**
* POSIX-style suffix: `aa`…`zz` (676 files), then `aaa`, `aab`, … as needed.
* @param {string} prefix
* @param {number} i 0-based output index
*/
function splitSuffix(prefix, i) { function splitSuffix(prefix, i) {
const a = 'abcdefghijklmnopqrstuvwxyz' const a = 'abcdefghijklmnopqrstuvwxyz'
const hi = Math.floor(i / 26) % 26 let idx = i
const lo = i % 26 let len = 2
return prefix + a[hi] + a[lo] let span = 26 ** len
while (idx >= span) {
idx -= span
len++
span = 26 ** len
}
let s = ''
let n = idx
for (let p = 0; p < len; p++) {
s = a[n % 26] + s
n = Math.floor(n / 26)
}
return prefix + s
} }
async function run(ctx, argv) { async function run(ctx, argv) {
+5 -2
View File
@@ -88,11 +88,14 @@ function bareOsEmitRaw(ctx, chunk) {
} }
/** /**
* Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host spawn). * Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host fork of arbitrary binaries).
* Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation, * Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation,
* 64 invocations per run. Exceeding limits is a fatal error (exit 125). * 64 invocations per run. Exceeding limits is a fatal error (exit 125).
* Supports -0/--null, -n, -L (lines per invocation; mutually exclusive with -n), -I repl (replace repl in utility argv; implies -n 1 unless -n given). * Supports -0/--null, -n, -L (lines per invocation; mutually exclusive with -n), -I repl (replace repl in utility argv; implies -n 1 unless -n given).
* -P N runs up to N batches in parallel (each batch uses a shallow ctx clone so exitCode does not race). * -P N runs up to N batches in parallel (each batch uses a shallow ctx clone so exitCode does not race); parallelism is still in-process
* over runBinCommand unless the booter/worker stack offloads specific /bin basenames (see BARE_OS_BIN_WORKER_*).
* For explicit host subprocess offload of whitelisted utilities, use ctx.bareOsTrySpawnHostSubprocess from custom scripts with
* BARE_OS_BIN_WORKER_ALLOW / delegate policy — not automatic from xargs.
* Max -P is min(requested, BARE_OS_XARGS_MAX_PROCS env, 32); default cap 8 when env unset. * Max -P is min(requested, BARE_OS_XARGS_MAX_PROCS env, 32); default cap 8 when env unset.
*/ */
@@ -1,6 +1,6 @@
{ {
"schemaVersion": 8, "schemaVersion": 8,
"ctxApiVersion": "1.44.0", "ctxApiVersion": "1.45.0",
"posixProfile": { "posixProfile": {
"id": "bare-os-posix-like", "id": "bare-os-posix-like",
"version": "1.0.9" "version": "1.0.9"
@@ -32,7 +32,19 @@
"namesCsv": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown" "namesCsv": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,recvfrom,sendmsg,recvmsg,shutdown"
}, },
"socketMsgSurface": { "socketMsgSurface": {
"schema": 2, "schema": 3,
"ancillaryControl": {
"supported": false,
"errno": "ENOTSUP",
"rejectKeys": [
"cmsgs",
"control",
"controllen",
"msgHdr.control",
"msgHdr.cmsgs"
],
"note": "Non-empty ancillary fields on sendmsg rejected; recvmsg controllen 0."
},
"sendmsg": { "bridgePartial": true, "defaultErrno": "ENOTSUP" }, "sendmsg": { "bridgePartial": true, "defaultErrno": "ENOTSUP" },
"recvmsg": { "bridgePartial": true, "defaultErrno": "ENOTSUP" } "recvmsg": { "bridgePartial": true, "defaultErrno": "ENOTSUP" }
}, },
@@ -7,36 +7,36 @@
"hypercoreIdEncoding" "hypercoreIdEncoding"
] ]
}, },
{
"path": "/lib/bare/bundles/safetyCatch.js",
"keys": [
"safetyCatch"
]
},
{ {
"path": "/lib/bare/bundles/b4a.js", "path": "/lib/bare/bundles/b4a.js",
"keys": [ "keys": [
"b4a" "b4a"
] ]
}, },
{
"path": "/lib/bare/bundles/safetyCatch.js",
"keys": [
"safetyCatch"
]
},
{ {
"path": "/lib/bare/bundles/compactEncoding.js", "path": "/lib/bare/bundles/compactEncoding.js",
"keys": [ "keys": [
"compactEncoding" "compactEncoding"
] ]
}, },
{
"path": "/lib/bare/bundles/bareUrl.js",
"keys": [
"bareUrl"
]
},
{ {
"path": "/lib/bare/bundles/protomux.js", "path": "/lib/bare/bundles/protomux.js",
"keys": [ "keys": [
"protomux" "protomux"
] ]
}, },
{
"path": "/lib/bare/bundles/bareUrl.js",
"keys": [
"bareUrl"
]
},
{ {
"path": "/lib/bare/bundles/barePath.js", "path": "/lib/bare/bundles/barePath.js",
"keys": [ "keys": [
@@ -74,9 +74,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareAddonResolve.js", "path": "/lib/bare/bundles/bareReadline.js",
"keys": [ "keys": [
"bareAddonResolve" "bareReadline"
] ]
}, },
{ {
@@ -86,15 +86,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareReadline.js", "path": "/lib/bare/bundles/bareAddonResolve.js",
"keys": [ "keys": [
"bareReadline" "bareAddonResolve"
]
},
{
"path": "/lib/bare/bundles/bareApk.js",
"keys": [
"bareApk"
] ]
}, },
{ {
@@ -109,12 +103,6 @@
"bareAtomics" "bareAtomics"
] ]
}, },
{
"path": "/lib/bare/bundles/bareAppKit.js",
"keys": [
"bareAppKit"
]
},
{ {
"path": "/lib/bare/bundles/bareAssert.js", "path": "/lib/bare/bundles/bareAssert.js",
"keys": [ "keys": [
@@ -122,9 +110,15 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareBmp.js", "path": "/lib/bare/bundles/bareApk.js",
"keys": [ "keys": [
"bareBmp" "bareApk"
]
},
{
"path": "/lib/bare/bundles/bareAppKit.js",
"keys": [
"bareAppKit"
] ]
}, },
{ {
@@ -133,12 +127,24 @@
"fetch" "fetch"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBmp.js",
"keys": [
"bareBmp"
]
},
{ {
"path": "/lib/bare/bundles/bareBundleCompile.js", "path": "/lib/bare/bundles/bareBundleCompile.js",
"keys": [ "keys": [
"bareBundleCompile" "bareBundleCompile"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBuffer.js",
"keys": [
"bareBuffer"
]
},
{ {
"path": "/lib/bare/bundles/bareBluetoothApple.js", "path": "/lib/bare/bundles/bareBluetoothApple.js",
"keys": [ "keys": [
@@ -151,30 +157,24 @@
"bareBundle" "bareBundle"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBuffer.js",
"keys": [
"bareBuffer"
]
},
{ {
"path": "/lib/bare/bundles/bareBundleEvaluate.js", "path": "/lib/bare/bundles/bareBundleEvaluate.js",
"keys": [ "keys": [
"bareBundleEvaluate" "bareBundleEvaluate"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBoot.js",
"keys": [
"bareBoot"
]
},
{ {
"path": "/lib/bare/bundles/bareConsole.js", "path": "/lib/bare/bundles/bareConsole.js",
"keys": [ "keys": [
"bareConsole" "bareConsole"
] ]
}, },
{
"path": "/lib/bare/bundles/bareBoot.js",
"keys": [
"bareBoot"
]
},
{ {
"path": "/lib/bare/bundles/bareBundleId.js", "path": "/lib/bare/bundles/bareBundleId.js",
"keys": [ "keys": [
@@ -187,18 +187,18 @@
"bareChannel" "bareChannel"
] ]
}, },
{
"path": "/lib/bare/bundles/bareDelta.js",
"keys": [
"bareDelta"
]
},
{ {
"path": "/lib/bare/bundles/bareDebugLog.js", "path": "/lib/bare/bundles/bareDebugLog.js",
"keys": [ "keys": [
"bareDebugLog" "bareDebugLog"
] ]
}, },
{
"path": "/lib/bare/bundles/bareDelta.js",
"keys": [
"bareDelta"
]
},
{ {
"path": "/lib/bare/bundles/bareDaemon.js", "path": "/lib/bare/bundles/bareDaemon.js",
"keys": [ "keys": [
@@ -217,6 +217,12 @@
"bareDns" "bareDns"
] ]
}, },
{
"path": "/lib/bare/bundles/bareCov.js",
"keys": [
"bareCov"
]
},
{ {
"path": "/lib/bare/bundles/bareEnv.js", "path": "/lib/bare/bundles/bareEnv.js",
"keys": [ "keys": [
@@ -235,12 +241,6 @@
"bareExif" "bareExif"
] ]
}, },
{
"path": "/lib/bare/bundles/bareCov.js",
"keys": [
"bareCov"
]
},
{ {
"path": "/lib/bare/bundles/bareFfmpeg.js", "path": "/lib/bare/bundles/bareFfmpeg.js",
"keys": [ "keys": [
@@ -260,9 +260,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareGif.js", "path": "/lib/bare/bundles/bareFileLogger.js",
"keys": [ "keys": [
"bareGif" "bareFileLogger"
] ]
}, },
{ {
@@ -272,9 +272,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareFileLogger.js", "path": "/lib/bare/bundles/bareGif.js",
"keys": [ "keys": [
"bareFileLogger" "bareGif"
] ]
}, },
{ {
@@ -290,9 +290,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareHttpParser.js", "path": "/lib/bare/bundles/bareFs.js",
"keys": [ "keys": [
"bareHttpParser" "bareFs"
] ]
}, },
{ {
@@ -301,24 +301,18 @@
"bareGtk" "bareGtk"
] ]
}, },
{
"path": "/lib/bare/bundles/bareHttpParser.js",
"keys": [
"bareHttpParser"
]
},
{ {
"path": "/lib/bare/bundles/bareIco.js", "path": "/lib/bare/bundles/bareIco.js",
"keys": [ "keys": [
"bareIco" "bareIco"
] ]
}, },
{
"path": "/lib/bare/bundles/bareFs.js",
"keys": [
"bareFs"
]
},
{
"path": "/lib/bare/bundles/bareHttp1.js",
"keys": [
"bareHttp1"
]
},
{ {
"path": "/lib/bare/bundles/bareImageResample.js", "path": "/lib/bare/bundles/bareImageResample.js",
"keys": [ "keys": [
@@ -332,9 +326,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareHttps.js", "path": "/lib/bare/bundles/bareHttp1.js",
"keys": [ "keys": [
"bareHttps" "bareHttp1"
] ]
}, },
{ {
@@ -344,9 +338,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareIpc.js", "path": "/lib/bare/bundles/bareHttps.js",
"keys": [ "keys": [
"bareIpc" "bareHttps"
] ]
}, },
{ {
@@ -355,6 +349,18 @@
"bareIntl" "bareIntl"
] ]
}, },
{
"path": "/lib/bare/bundles/bareIpc.js",
"keys": [
"bareIpc"
]
},
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{ {
"path": "/lib/bare/bundles/bareInspector.js", "path": "/lib/bare/bundles/bareInspector.js",
"keys": [ "keys": [
@@ -367,12 +373,6 @@
"bareLief" "bareLief"
] ]
}, },
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{ {
"path": "/lib/bare/bundles/bareLink.js", "path": "/lib/bare/bundles/bareLink.js",
"keys": [ "keys": [
@@ -385,30 +385,30 @@
"bareMake" "bareMake"
] ]
}, },
{
"path": "/lib/bare/bundles/bareModule.js",
"keys": [
"bareModule"
]
},
{ {
"path": "/lib/bare/bundles/bareModuleResolve.js", "path": "/lib/bare/bundles/bareModuleResolve.js",
"keys": [ "keys": [
"bareModuleResolve" "bareModuleResolve"
] ]
}, },
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{ {
"path": "/lib/bare/bundles/bareModuleTraverse.js", "path": "/lib/bare/bundles/bareModuleTraverse.js",
"keys": [ "keys": [
"bareModuleTraverse" "bareModuleTraverse"
] ]
}, },
{
"path": "/lib/bare/bundles/bareModule.js",
"keys": [
"bareModule"
]
},
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{ {
"path": "/lib/bare/bundles/bareNdk.js", "path": "/lib/bare/bundles/bareNdk.js",
"keys": [ "keys": [
@@ -439,12 +439,6 @@
"bareNet" "bareNet"
] ]
}, },
{
"path": "/lib/bare/bundles/bareMedia.js",
"keys": [
"bareMedia"
]
},
{ {
"path": "/lib/bare/bundles/bareOs.js", "path": "/lib/bare/bundles/bareOs.js",
"keys": [ "keys": [
@@ -452,15 +446,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/barePerformance.js", "path": "/lib/bare/bundles/bareMedia.js",
"keys": [ "keys": [
"barePerformance" "bareMedia"
]
},
{
"path": "/lib/bare/bundles/barePackDrive.js",
"keys": [
"barePackDrive"
] ]
}, },
{ {
@@ -469,12 +457,30 @@
"barePack" "barePack"
] ]
}, },
{
"path": "/lib/bare/bundles/barePerformance.js",
"keys": [
"barePerformance"
]
},
{
"path": "/lib/bare/bundles/bareNodeRuntime.js",
"keys": [
"bareNodeRuntime"
]
},
{ {
"path": "/lib/bare/bundles/barePng.js", "path": "/lib/bare/bundles/barePng.js",
"keys": [ "keys": [
"barePng" "barePng"
] ]
}, },
{
"path": "/lib/bare/bundles/barePackDrive.js",
"keys": [
"barePackDrive"
]
},
{ {
"path": "/lib/bare/bundles/barePipe.js", "path": "/lib/bare/bundles/barePipe.js",
"keys": [ "keys": [
@@ -488,15 +494,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareNodeRuntime.js", "path": "/lib/bare/bundles/bareQuerystring.js",
"keys": [ "keys": [
"bareNodeRuntime" "bareQuerystring"
]
},
{
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareDev"
] ]
}, },
{ {
@@ -506,9 +506,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareQuerystring.js", "path": "/lib/bare/bundles/bareQueueMicrotask.js",
"keys": [ "keys": [
"bareQuerystring" "bareQueueMicrotask"
] ]
}, },
{ {
@@ -523,24 +523,12 @@
"bareProcess" "bareProcess"
] ]
}, },
{
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
"keys": [
"bareQueueMicrotask"
]
},
{ {
"path": "/lib/bare/bundles/barePromClient.js", "path": "/lib/bare/bundles/barePromClient.js",
"keys": [ "keys": [
"barePromClient" "barePromClient"
] ]
}, },
{
"path": "/lib/bare/bundles/bareRpc.js",
"keys": [
"bareRpc"
]
},
{ {
"path": "/lib/bare/bundles/bareRuntime.js", "path": "/lib/bare/bundles/bareRuntime.js",
"keys": [ "keys": [
@@ -548,15 +536,9 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareSemver.js", "path": "/lib/bare/bundles/bareRpc.js",
"keys": [ "keys": [
"bareSemver" "bareRpc"
]
},
{
"path": "/lib/bare/bundles/bareSdl.js",
"keys": [
"bareSdl"
] ]
}, },
{ {
@@ -565,6 +547,18 @@
"bareRepl" "bareRepl"
] ]
}, },
{
"path": "/lib/bare/bundles/bareSemver.js",
"keys": [
"bareSemver"
]
},
{
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareDev"
]
},
{ {
"path": "/lib/bare/bundles/bareSidecar.js", "path": "/lib/bare/bundles/bareSidecar.js",
"keys": [ "keys": [
@@ -577,6 +571,12 @@
"bareSignals" "bareSignals"
] ]
}, },
{
"path": "/lib/bare/bundles/bareSdl.js",
"keys": [
"bareSdl"
]
},
{ {
"path": "/lib/bare/bundles/bareRun.js", "path": "/lib/bare/bundles/bareRun.js",
"keys": [ "keys": [
@@ -589,60 +589,60 @@
"bareStringDecoder" "bareStringDecoder"
] ]
}, },
{
"path": "/lib/bare/bundles/bareStorage.js",
"keys": [
"bareStorage"
]
},
{ {
"path": "/lib/bare/bundles/bareStream.js", "path": "/lib/bare/bundles/bareStream.js",
"keys": [ "keys": [
"bareStream" "bareStream"
] ]
}, },
{
"path": "/lib/bare/bundles/bareStdio.js",
"keys": [
"bareStdio"
]
},
{ {
"path": "/lib/bare/bundles/bareSvg.js", "path": "/lib/bare/bundles/bareSvg.js",
"keys": [ "keys": [
"bareSvg" "bareSvg"
] ]
}, },
{
"path": "/lib/bare/bundles/bareStdio.js",
"keys": [
"bareStdio"
]
},
{
"path": "/lib/bare/bundles/bareStorage.js",
"keys": [
"bareStorage"
]
},
{ {
"path": "/lib/bare/bundles/bareStructuredClone.js", "path": "/lib/bare/bundles/bareStructuredClone.js",
"keys": [ "keys": [
"bareStructuredClone" "bareStructuredClone"
] ]
}, },
{
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareSystemLogger"
]
},
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{ {
"path": "/lib/bare/bundles/bareTiff.js", "path": "/lib/bare/bundles/bareTiff.js",
"keys": [ "keys": [
"bareTiff" "bareTiff"
] ]
}, },
{
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareSystemLogger"
]
},
{ {
"path": "/lib/bare/bundles/bareSubprocess.js", "path": "/lib/bare/bundles/bareSubprocess.js",
"keys": [ "keys": [
"bareSubprocess" "bareSubprocess"
] ]
}, },
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{ {
"path": "/lib/bare/bundles/bareTcp.js", "path": "/lib/bare/bundles/bareTcp.js",
"keys": [ "keys": [
@@ -655,18 +655,18 @@
"bareThread" "bareThread"
] ]
}, },
{
"path": "/lib/bare/bundles/bareTimers.js",
"keys": [
"bareTimers"
]
},
{ {
"path": "/lib/bare/bundles/bareTpl.js", "path": "/lib/bare/bundles/bareTpl.js",
"keys": [ "keys": [
"bareTpl" "bareTpl"
] ]
}, },
{
"path": "/lib/bare/bundles/bareTimers.js",
"keys": [
"bareTimers"
]
},
{ {
"path": "/lib/bare/bundles/bareType.js", "path": "/lib/bare/bundles/bareType.js",
"keys": [ "keys": [
@@ -691,12 +691,6 @@
"bareTty" "bareTty"
] ]
}, },
{
"path": "/lib/bare/bundles/bareV8.js",
"keys": [
"bareV8"
]
},
{ {
"path": "/lib/bare/bundles/bareUnpack.js", "path": "/lib/bare/bundles/bareUnpack.js",
"keys": [ "keys": [
@@ -704,9 +698,15 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareUnionBundle.js", "path": "/lib/bare/bundles/bareV8.js",
"keys": [ "keys": [
"bareUnionBundle" "bareV8"
]
},
{
"path": "/lib/bare/bundles/bareVm.js",
"keys": [
"bareVm"
] ]
}, },
{ {
@@ -722,21 +722,15 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareVm.js", "path": "/lib/bare/bundles/bareUnionBundle.js",
"keys": [ "keys": [
"bareVm" "bareUnionBundle"
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareUtils.js", "path": "/lib/bare/bundles/bareV8ToIstanbul.js",
"keys": [ "keys": [
"bareUtils" "bareV8ToIstanbul"
]
},
{
"path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [
"bareWebKitGtk"
] ]
}, },
{ {
@@ -745,6 +739,12 @@
"bareWebp" "bareWebp"
] ]
}, },
{
"path": "/lib/bare/bundles/bareUtils.js",
"keys": [
"bareUtils"
]
},
{ {
"path": "/lib/bare/bundles/bareWhich.js", "path": "/lib/bare/bundles/bareWhich.js",
"keys": [ "keys": [
@@ -752,15 +752,15 @@
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareWinUi.js", "path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [ "keys": [
"bareWinUi" "bareWebKitGtk"
] ]
}, },
{ {
"path": "/lib/bare/bundles/bareV8ToIstanbul.js", "path": "/lib/bare/bundles/bareWinUi.js",
"keys": [ "keys": [
"bareV8ToIstanbul" "bareWinUi"
] ]
}, },
{ {
@@ -775,6 +775,12 @@
"bareZlib" "bareZlib"
] ]
}, },
{
"path": "/lib/bare/bundles/bareWs.js",
"keys": [
"bareWs"
]
},
{ {
"path": "/lib/bare/bundles/bareZmq.js", "path": "/lib/bare/bundles/bareZmq.js",
"keys": [ "keys": [
@@ -786,12 +792,6 @@
"keys": [ "keys": [
"bareWorker" "bareWorker"
] ]
},
{
"path": "/lib/bare/bundles/bareWs.js",
"keys": [
"bareWs"
]
} }
], ],
"bundleStats": { "bundleStats": {
@@ -1595,8 +1595,8 @@
], ],
"bundleProvenance": { "bundleProvenance": {
"schemaVersion": 1, "schemaVersion": 1,
"generatedAt": "2026-04-05T05:06:01.462Z", "generatedAt": "2026-04-05T05:30:46.127Z",
"gitCommit": "f79db043130bdbfffa8bcca66fd6252c9d17205d", "gitCommit": "c64910d72ee5547302fce1717ffedd42594e4bc4",
"nodeVersion": "v22.22.0", "nodeVersion": "v22.22.0",
"bundleTier": "all", "bundleTier": "all",
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json", "normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
@@ -1,6 +1,6 @@
{ {
"schema": 1, "schema": 1,
"atMs": 1775365560517, "atMs": 1775367045352,
"commands": [ "commands": [
"arch", "arch",
"awk", "awk",
File diff suppressed because one or more lines are too long
+6
View File
@@ -251,6 +251,12 @@ Writes **[`docs/audit/holepunch-clone-sync-report.json`](../docs/audit/holepunch
Runs on every **`pretest`**. For each repo basename listed in **`repos`** inside **[`docs/audit/holepunch-drift-repos.json`](../docs/audit/holepunch-drift-repos.json)**, checks that **`origin/main`** is an ancestor of **`HEAD`** (clone not behind remote). With an empty **`repos`** array, the script is a no-op. The same file carries **`suggestedCriticalRepos`** (wire stack hints); copy those into **`repos`** when you maintain local clones and want CI to enforce freshness. Set **`BARE_OS_HOLEPUNCH_DRIFT_CHECK=0`** to skip the script entirely (e.g. offline sandboxes). **`sync-holepunch-clones.mjs`** echoes **`suggestedCriticalRepos`** into **`holepunch-clone-sync-report.json`** for review. Runs on every **`pretest`**. For each repo basename listed in **`repos`** inside **[`docs/audit/holepunch-drift-repos.json`](../docs/audit/holepunch-drift-repos.json)**, checks that **`origin/main`** is an ancestor of **`HEAD`** (clone not behind remote). With an empty **`repos`** array, the script is a no-op. The same file carries **`suggestedCriticalRepos`** (wire stack hints); copy those into **`repos`** when you maintain local clones and want CI to enforce freshness. Set **`BARE_OS_HOLEPUNCH_DRIFT_CHECK=0`** to skip the script entirely (e.g. offline sandboxes). **`sync-holepunch-clones.mjs`** echoes **`suggestedCriticalRepos`** into **`holepunch-clone-sync-report.json`** for review.
## `gen-bare-holepunch-catalog.mjs`
**Usage:** `node scripts/gen-bare-holepunch-catalog.mjs` (also **`npm run gen:bare-catalog`** / **`npm run gen:bare-catalog:check`** from the repo root)
Scans a local Holepunch mirror ( **`HOLEPUNCH_MIRROR`** or default under the repo) for **`holepunchto/bare-*`** repos, merges npm **`latest`** metadata and **[`scripts/bare-catalog-overrides.json`](bare-catalog-overrides.json)**, and writes **[`docs/bare-holepunch-catalog.json`](../docs/bare-holepunch-catalog.json)**. Follow with **`npm run sync:bare-manifest`** and **`npm install`** so **[`packages/bare-os-booter/lib/bare-module-manifest.json`](../packages/bare-os-booter/lib/bare-module-manifest.json)** and booter **`optionalDependencies`** stay aligned. CI **`gen:bare-catalog:check`** ensures the committed catalog does not drift.
## `verify-bundle-throws.mjs` ## `verify-bundle-throws.mjs`
**Usage:** `node scripts/verify-bundle-throws.mjs` **Usage:** `node scripts/verify-bundle-throws.mjs`