feat(booter): POSIX/P2P roadmap — syscalls v4, mirror VFS, seeder snapshot hints
- Bump ctx API to 1.31.0; extend /proc/bare_os/syscalls.json schema 4 (fdModel, signalModel) - Add /mirror/aux* routing for auxiliary Hyperdrives; optional BLAKE2b-keyed /bin cache (BARE_OS_VFS_BIN_CACHE_BLAKE2B) - Wire seeder snapshotHintsJson from BARE_OS_SEED_* env; add seeder unit tests - Shell: trap -p; docs for jobs/bg/trap; sync schemas, examples, compatibility matrix, handbook ch.9 - Coreutils: Issue 7 man option rows for cp/mv/ln/find/grep/sed/awk/tar/test/true; xcu-issue7-sweep tests - Docs: env appendix, vault-threat-model, node-vs-bare-host-matrix, test:bare, CHANGELOG 1.31.0
This commit is contained in:
@@ -16,6 +16,7 @@ Start at the **[documentation home](docs/README.md)** for role-based navigation
|
||||
| Architecture narrative | [handbook/README.md](handbook/README.md) |
|
||||
| Extend `/bin`, `ctx`, Pear | [developer-guide/README.md](developer-guide/README.md) |
|
||||
| File-level reference index | [docs/reference/README.md](docs/reference/README.md) |
|
||||
| Node vs Bare test hosts | [docs/reference/node-vs-bare-host-matrix.md](docs/reference/node-vs-bare-host-matrix.md) |
|
||||
| Kernel boundaries and boot steps | [docs/architecture/KERNEL_CONTRACT.md](docs/architecture/KERNEL_CONTRACT.md) |
|
||||
| Doc contribution guide | [docs/CONTRIBUTING-DOCS.md](docs/CONTRIBUTING-DOCS.md) |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generatedAt": "2026-04-05T01:31:52.581Z",
|
||||
"generatedAt": "2026-04-05T01:58:32.353Z",
|
||||
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
|
||||
"buildTool": "packages/bare-os-bare-libs/build.mjs",
|
||||
"bundles": [
|
||||
|
||||
@@ -48,6 +48,7 @@ This directory holds the split **file-by-file inventory** that used to live in t
|
||||
- **Bits, env, `/proc`, and `ctx` map** — [Kernel capabilities index](kernel-capabilities-index.md)
|
||||
- **`ctx` API versioning** — [ctx-api-versioning.md](ctx-api-versioning.md)
|
||||
- **Version alignment** — [Compatibility matrix](compatibility-matrix.md)
|
||||
- **Node vs Bare test hosts** — [node-vs-bare-host-matrix.md](node-vs-bare-host-matrix.md)
|
||||
- **Legacy ↔ canonical names** — [Naming alias matrix](naming-alias-matrix.md)
|
||||
- **Kernel program status tables** — [Feature roadmap status](feature-roadmap.md)
|
||||
- **VFS path classes (policy sketch)** — [vfs-path-classes.md](vfs-path-classes.md)
|
||||
|
||||
@@ -14,7 +14,7 @@ Single place to compare **protocol**, **booter `ctx` API**, **feature-bit docume
|
||||
|
||||
## Version artifacts
|
||||
|
||||
**`bareOsCtxApiVersion`** (current stock: **`1.30.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.31.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).
|
||||
|
||||
@@ -24,9 +24,9 @@ Single place to compare **protocol**, **booter `ctx` API**, **feature-bit docume
|
||||
|
||||
**Protocol package** — Workspace version in [`bare-os-protocol` `package.json`](../../packages/bare-os-protocol/package.json). Pair it with seeder and booter releases when you change wire behavior.
|
||||
|
||||
**POSIX-like profile** — **`BARE_OS_POSIX_PROFILE_VERSION`** (**`1.0.0`**) 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`** (schema **3**).
|
||||
**POSIX-like profile** — **`BARE_OS_POSIX_PROFILE_VERSION`** (**`1.0.0`**) 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`** (schema **4**).
|
||||
|
||||
**`/proc/bare_os/syscalls.json`** — Schema **3** adds **`opsDetail`** (category + stability per op), full **`errnoHints`** table, and **`posixProfile`**. 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 **4** extends schema **3** with **`fdModel`** (logical FD table pointers) and **`signalModel`** (synthetic signal vocabulary). Schema **3** added **`opsDetail`**, **`errnoHints`**, and **`posixProfile`**. 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).
|
||||
|
||||
---
|
||||
|
||||
@@ -39,6 +39,7 @@ Single place to compare **protocol**, **booter `ctx` API**, **feature-bit docume
|
||||
|
||||
## See also
|
||||
|
||||
- [`node-vs-bare-host-matrix.md`](./node-vs-bare-host-matrix.md)
|
||||
- [`kernel-extensions.md`](./kernel-extensions.md)
|
||||
- [`kernel-capabilities-index.md`](./kernel-capabilities-index.md)
|
||||
- [Handbook ch.11 — Kernel program](../../handbook/11-kernel-program-and-research.md)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// 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`. */
|
||||
export const BARE_OS_CTX_API_CLIENT_VERSION = '1.30.0' as const
|
||||
export const BARE_OS_CTX_API_CLIENT_VERSION = '1.31.0' as const
|
||||
|
||||
/** 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
|
||||
|
||||
/** Approximate count of `bareOs…` members in the DTS (diagnostic only; regenerate on contract edits). */
|
||||
export const BARE_OS_CTX_DTS_BAREOS_MEMBER_APPROX = 122 as const
|
||||
export const BARE_OS_CTX_DTS_BAREOS_MEMBER_APPROX = 127 as const
|
||||
|
||||
/** Byte length of `bare-os-ctx.d.ts` when this file was generated. */
|
||||
export const BARE_OS_CTX_DTS_BYTES = 14640 as const
|
||||
export const BARE_OS_CTX_DTS_BYTES = 15264 as const
|
||||
|
||||
/** Pointers for external client generators (OpenAPI / JSON Schema follow-ups). */
|
||||
export const BARE_OS_CTX_SCHEMA_HINT = {
|
||||
|
||||
@@ -16,6 +16,8 @@ Former **DOCUMENTATION.md** §14, §14a. [Reference index →](README.md)
|
||||
The list below is one **bullet per variable** in the form **name — component — meaning**. Values shown as defaults are what the stock tree assumes when the variable is unset; always confirm in source when debugging a forked image.
|
||||
|
||||
- `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_SNAPSHOT_HINTS_JSON` — Seeder — Optional JSON string; when set, passed verbatim as **`snapshotHintsJson`** (wins over **`BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG`**).
|
||||
- `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_BOOT_STORE` — Booter — Corestore for boot side (default: `~/.bare-os/corestore/booter`)
|
||||
@@ -41,12 +43,15 @@ The list below is one **bullet per variable** in the form **name — component
|
||||
- `MANWIDTH` — `/bin/man` — Wrap width for manual text (default `72`; minimum `40`)
|
||||
- `NO_COLOR` — `/bin/man` — If set, disable ANSI bold for section headings on a TTY
|
||||
|
||||
**Host → session passthrough** (booter copies into **`shellEnv`** when the host sets a non-empty value; canonical list in [`packages/bare-os-booter/index.js`](../../packages/bare-os-booter/index.js)): `BARE_OS_PIPELINE_MAX_STAGES`, `BARE_OS_PIPELINE_MAX_BYTES`, `BARE_OS_PIPELINE_MAX_LINES`, `BARE_OS_SHELL_STREAMING`, `BARE_OS_SHELL_STREAMING_MULT`, `BARE_OS_SHELL_CMDSUBST`, `BARE_OS_SHELL_CMDSUBST_MAX_BYTES`, `BARE_OS_SHELL_PARAM_EXPANSION`, `BARE_OS_SHELL_PARAM_EXPANSION_V2`, `BARE_OS_SHELL_PARAM_EXPANSION_V3`, `BARE_OS_ENV_DASH_S`, `BARE_OS_VFS_WATCH_PSEUDO`, `BARE_OS_VFS_WATCH_SWARM`, `BARE_OS_SHELL_LOCAL_DECLARE`, `BARE_OS_DIAGNOSTICS_SUBSCRIBE`, `BARE_OS_AUTOPASS_INVITE_URL`, `BARE_OS_BIN_WORKER_OFFLOAD`, `BARE_OS_BIN_WORKER_ALLOW`, `BARE_OS_BIN_WORKER_CPU_MS_MAX`, `BARE_OS_BOOT_PROFILE`, `BARE_OS_ONBOOT`, `BARE_OS_BOOT_STRICT`, `BARE_OS_RC_D_SKIP`, `BARE_OS_BOOT_MINIMAL`, `BARE_OS_BOOT_SKIP`, `BARE_OS_BOOT_SAFE_MODE`, `BARE_OS_BOOT_TRANSACTION_JOURNAL`, `BARE_OS_BOOT_CHECKPOINT`, `BARE_OS_BOOT_DRY_RUN`, `BARE_OS_BOOT_POLICY_PATH`, `BARE_OS_BOOT_ROLLBACK_APPLY`, `BARE_OS_BOOT_BUNDLE_DIGEST_HEX`, `BARE_OS_REQUIRE_CTX_API_MIN`, `BARE_OS_BOOT_ABI_STRICT`, `BARE_OS_LOADER_AUDIT`, `BARE_OS_DELEGATE_TRACE`, `BARE_OS_DNS_PROFILE`, `BARE_OS_BOOT_TRACE`, `BARE_OS_KERNEL_PROGRAM_PROC_JSON`, `BARE_OS_GIANT_PHASE_PROGRAM_JSON`, `BARE_OS_KERNEL_SELFTEST`, `BARE_OS_SELFTEST_FORMAT`, `BARE_OS_AUDIT`, `BARE_OS_AUDIT_JSON`, `BARE_OS_AUDIT_REDACT`, `BARE_OS_IMAGE_DIGEST`, `BARE_OS_EXEC_MAX_DEPTH`, `BARE_OS_EXEC_LINE_BUDGET_MS`, `BARE_OS_IPC_MAX_BYTES`, `BARE_OS_IPC_CHANNEL_MAX_BYTES`, `BARE_OS_IPC_RPC_TOKEN`, `BARE_OS_IPC_FANOUT`, `BARE_OS_IPC_JSON_MAX_BYTES`, `BARE_OS_IPC_NAMESPACE`, `BARE_OS_VFS_WATCH`, `BARE_OS_VFS_UNION_PREFIXES`, `BARE_OS_VFS_UNION_WRITE_DENY`, `BARE_OS_VFS_HYPERBLOBS_DEDUP`, `BARE_OS_VFS_BIN_CACHE`, `BARE_OS_BOOT_ALLOWLIST`, `BARE_OS_BOOT_MANIFEST`, `BARE_OS_BOOT_MANIFEST_SIGN`, `BARE_OS_BOOT_MANIFEST_PUBKEY_HEX`, `BARE_OS_BOOT_POLICY`, `BARE_OS_BOOT_POLICY_STRICT`, `BARE_OS_LAZY_PERSONAL_DRIVE`, `BARE_OS_SYSTEM_REVISION_ID`, `BARE_OS_SYSTEM_REVISION_PENDING`, `BARE_OS_SYSTEM_SLOT`, `BARE_OS_DELEGATE_ALLOW`, `BARE_OS_DELEGATE_MAX_PER_MIN`, `BARE_OS_DELEGATE_MAX_CONCURRENT`, `BARE_OS_DELEGATE_GIT_MAX_PER_MIN`, `BARE_OS_DELEGATE_CURL_MAX_PER_MIN`, `BARE_OS_DELEGATE_WGET_MAX_PER_MIN`, `BARE_OS_DELEGATE_SYSTEMCTL_MAX_PER_MIN`, `BARE_OS_DELEGATE_GIT_MAX_CONCURRENT`, `BARE_OS_DELEGATE_CURL_MAX_CONCURRENT`, `BARE_OS_DELEGATE_WGET_MAX_CONCURRENT`, `BARE_OS_DELEGATE_SYSTEMCTL_MAX_CONCURRENT`, `BARE_OS_DELEGATE_AUDIT_ONLY`, `BARE_OS_DNS_ALLOWLIST`, `BARE_OS_KERNEL_HOT_RELOAD`, `BARE_OS_KERNEL_EXT_D_HOT_RELOAD`, `BARE_OS_SANDBOX_SCRIPT`, `BARE_OS_SANDBOX_WORKER`, `BARE_OS_INITD_MAX_PARALLEL`, `BARE_OS_INITD_JOURNAL_MAX_LINES`, `BARE_OS_URANDOM_CRYPTO`, `BARE_OS_TELEMETRY_NDJSON`, `BARE_OS_TELEMETRY_OTEL_JSONL`, `BARE_OS_PROC_POLL_MS`, `BARE_OS_TIMER_EVERY_MS_MONOTONIC`, `BARE_OS_TRACE_ID`, `BARE_OS_SEED_RPC_HANDSHAKE`, `BARE_OS_SEED_CAP_STRICT`, `BARE_OS_SEED_CAP_FAIL`, `BARE_OS_OFFLINE_LKG_BOOT`, `BARE_OS_LKG_SYSTEM_KEY_HEX`, `BARE_OS_HOST_STORAGE_JSON`, `BARE_OS_BOOT_POLICY_DENY_EXEC_LINE_BUILTINS`, `BARE_OS_BOOT_POLICY_ALLOWED_CTX_METHODS`, `BARE_OS_SUBPROCESS_BRIDGE_JOBS_JSON`, `BARE_OS_IPC_AUDIT`, `BARE_OS_HTTP_ALLOWLIST`, `BARE_OS_HTTP_DENYLIST`, `BARE_OS_TLS_PIN_SHA256`, `BARE_OS_BARE_MODULES`, `BARE_OS_BARE_DRIVE_BUNDLES`, `BARE_OS_PEAR_CHANNEL`, `BARE_OS_PEAR_RELEASE`, `PEAR_CHANNEL`, `BARE_OS_FIND_EXEC_MAX`, `BARE_OS_XARGS_MAX_PROCS`, `BARE_OS_YES_MAX_LINES`, `BARE_OS_SHUF_MAX_LINES`, `BARE_OS_SPLIT_MAX_FILES`, `BARE_OS_NPROC`, `BARE_OS_BLIND_BOOTSTRAP_URL`, `BARE_OS_BLIND_BOOTSTRAP_JSON`, `BARE_OS_MIRROR_READ_KEY`, `BARE_OS_PEER_FIREWALL_E2E_JSON`, `BARE_OS_PEAR_SECURE_ENCLAVE_JSON`, `BARE_OS_ACCOUNT_KEY_ROTATION_STATE_JSON`, `BARE_OS_PEAR_TRUST_JSON`, `BARE_OS_HOST_BUNDLE_EVALUATE`, **`TERM`**, **`COLORTERM`**. *(Many additional operator JSON pointers and version pins are also copied from the same loop; see source.)*
|
||||
**Host → session passthrough** (booter copies into **`shellEnv`** when the host sets a non-empty value; canonical list in [`packages/bare-os-booter/index.js`](../../packages/bare-os-booter/index.js)): `BARE_OS_PIPELINE_MAX_STAGES`, `BARE_OS_PIPELINE_MAX_BYTES`, `BARE_OS_PIPELINE_MAX_LINES`, `BARE_OS_SHELL_STREAMING`, `BARE_OS_SHELL_STREAMING_MULT`, `BARE_OS_SHELL_CMDSUBST`, `BARE_OS_SHELL_CMDSUBST_MAX_BYTES`, `BARE_OS_SHELL_PARAM_EXPANSION`, `BARE_OS_SHELL_PARAM_EXPANSION_V2`, `BARE_OS_SHELL_PARAM_EXPANSION_V3`, `BARE_OS_ENV_DASH_S`, `BARE_OS_VFS_WATCH_PSEUDO`, `BARE_OS_VFS_WATCH_SWARM`, `BARE_OS_SHELL_LOCAL_DECLARE`, `BARE_OS_DIAGNOSTICS_SUBSCRIBE`, `BARE_OS_AUTOPASS_INVITE_URL`, `BARE_OS_BIN_WORKER_OFFLOAD`, `BARE_OS_BIN_WORKER_ALLOW`, `BARE_OS_BIN_WORKER_CPU_MS_MAX`, `BARE_OS_BOOT_PROFILE`, `BARE_OS_ONBOOT`, `BARE_OS_BOOT_STRICT`, `BARE_OS_RC_D_SKIP`, `BARE_OS_BOOT_MINIMAL`, `BARE_OS_BOOT_SKIP`, `BARE_OS_BOOT_SAFE_MODE`, `BARE_OS_BOOT_TRANSACTION_JOURNAL`, `BARE_OS_BOOT_CHECKPOINT`, `BARE_OS_BOOT_DRY_RUN`, `BARE_OS_BOOT_POLICY_PATH`, `BARE_OS_BOOT_ROLLBACK_APPLY`, `BARE_OS_BOOT_BUNDLE_DIGEST_HEX`, `BARE_OS_REQUIRE_CTX_API_MIN`, `BARE_OS_BOOT_ABI_STRICT`, `BARE_OS_LOADER_AUDIT`, `BARE_OS_DELEGATE_TRACE`, `BARE_OS_DNS_PROFILE`, `BARE_OS_BOOT_TRACE`, `BARE_OS_KERNEL_PROGRAM_PROC_JSON`, `BARE_OS_GIANT_PHASE_PROGRAM_JSON`, `BARE_OS_KERNEL_SELFTEST`, `BARE_OS_SELFTEST_FORMAT`, `BARE_OS_AUDIT`, `BARE_OS_AUDIT_JSON`, `BARE_OS_AUDIT_REDACT`, `BARE_OS_IMAGE_DIGEST`, `BARE_OS_EXEC_MAX_DEPTH`, `BARE_OS_EXEC_LINE_BUDGET_MS`, `BARE_OS_IPC_MAX_BYTES`, `BARE_OS_IPC_CHANNEL_MAX_BYTES`, `BARE_OS_IPC_RPC_TOKEN`, `BARE_OS_IPC_FANOUT`, `BARE_OS_IPC_JSON_MAX_BYTES`, `BARE_OS_IPC_NAMESPACE`, `BARE_OS_VFS_WATCH`, `BARE_OS_VFS_UNION_PREFIXES`, `BARE_OS_VFS_UNION_WRITE_DENY`, `BARE_OS_VFS_HYPERBLOBS_DEDUP`, `BARE_OS_VFS_BIN_CACHE`, `BARE_OS_VFS_BIN_CACHE_BLAKE2B`, `BARE_OS_VFS_ENFORCE_ACL`, `BARE_OS_VFS_BIN_INDEX_BUILD`, `BARE_OS_BOOT_ALLOWLIST`, `BARE_OS_BOOT_MANIFEST`, `BARE_OS_BOOT_MANIFEST_SIGN`, `BARE_OS_BOOT_MANIFEST_PUBKEY_HEX`, `BARE_OS_BOOT_POLICY`, `BARE_OS_BOOT_POLICY_STRICT`, `BARE_OS_LAZY_PERSONAL_DRIVE`, `BARE_OS_SYSTEM_REVISION_ID`, `BARE_OS_SYSTEM_REVISION_PENDING`, `BARE_OS_SYSTEM_SLOT`, `BARE_OS_DELEGATE_ALLOW`, `BARE_OS_DELEGATE_MAX_PER_MIN`, `BARE_OS_DELEGATE_MAX_CONCURRENT`, `BARE_OS_DELEGATE_GIT_MAX_PER_MIN`, `BARE_OS_DELEGATE_CURL_MAX_PER_MIN`, `BARE_OS_DELEGATE_WGET_MAX_PER_MIN`, `BARE_OS_DELEGATE_SYSTEMCTL_MAX_PER_MIN`, `BARE_OS_DELEGATE_GIT_MAX_CONCURRENT`, `BARE_OS_DELEGATE_CURL_MAX_CONCURRENT`, `BARE_OS_DELEGATE_WGET_MAX_CONCURRENT`, `BARE_OS_DELEGATE_SYSTEMCTL_MAX_CONCURRENT`, `BARE_OS_DELEGATE_AUDIT_ONLY`, `BARE_OS_DNS_ALLOWLIST`, `BARE_OS_KERNEL_HOT_RELOAD`, `BARE_OS_KERNEL_EXT_D_HOT_RELOAD`, `BARE_OS_SANDBOX_SCRIPT`, `BARE_OS_SANDBOX_WORKER`, `BARE_OS_INITD_MAX_PARALLEL`, `BARE_OS_INITD_JOURNAL_MAX_LINES`, `BARE_OS_URANDOM_CRYPTO`, `BARE_OS_TELEMETRY_NDJSON`, `BARE_OS_TELEMETRY_OTEL_JSONL`, `BARE_OS_PROC_POLL_MS`, `BARE_OS_TIMER_EVERY_MS_MONOTONIC`, `BARE_OS_TRACE_ID`, `BARE_OS_SEED_RPC_HANDSHAKE`, `BARE_OS_SEED_CAP_STRICT`, `BARE_OS_SEED_CAP_FAIL`, `BARE_OS_OFFLINE_LKG_BOOT`, `BARE_OS_LKG_SYSTEM_KEY_HEX`, `BARE_OS_HOST_STORAGE_JSON`, `BARE_OS_BOOT_POLICY_DENY_EXEC_LINE_BUILTINS`, `BARE_OS_BOOT_POLICY_ALLOWED_CTX_METHODS`, `BARE_OS_SUBPROCESS_BRIDGE_JOBS_JSON`, `BARE_OS_IPC_AUDIT`, `BARE_OS_HTTP_ALLOWLIST`, `BARE_OS_HTTP_DENYLIST`, `BARE_OS_TLS_PIN_SHA256`, `BARE_OS_BARE_MODULES`, `BARE_OS_BARE_DRIVE_BUNDLES`, `BARE_OS_PEAR_CHANNEL`, `BARE_OS_PEAR_RELEASE`, `PEAR_CHANNEL`, `BARE_OS_FIND_EXEC_MAX`, `BARE_OS_XARGS_MAX_PROCS`, `BARE_OS_YES_MAX_LINES`, `BARE_OS_SHUF_MAX_LINES`, `BARE_OS_SPLIT_MAX_FILES`, `BARE_OS_NPROC`, `BARE_OS_BLIND_BOOTSTRAP_URL`, `BARE_OS_BLIND_BOOTSTRAP_JSON`, `BARE_OS_MIRROR_READ_KEY`, `BARE_OS_PEER_FIREWALL_E2E_JSON`, `BARE_OS_PEAR_SECURE_ENCLAVE_JSON`, `BARE_OS_ACCOUNT_KEY_ROTATION_STATE_JSON`, `BARE_OS_PEAR_TRUST_JSON`, `BARE_OS_HOST_BUNDLE_EVALUATE`, **`TERM`**, **`COLORTERM`**. *(Many additional operator JSON pointers and version pins are also copied from the same loop; see source.)*
|
||||
|
||||
- `BARE_OS_VFS_UNION_PREFIXES` — Booter / VFS — Comma-separated logical path prefixes where **`readFile`** may union system + overlay sources.
|
||||
- `BARE_OS_VFS_UNION_WRITE_DENY` — Booter / VFS — When **`1`** / **`true`**, block **`writeFile`** / **`unlink`** on paths under union read prefixes (read-only union overlay).
|
||||
- `BARE_OS_IPC_CHANNEL_MAX_BYTES` — Booter / IPC — Optional JSON map **`{"fifoName": maxBytes}`** (or legacy comma form) capping buffered bytes per FIFO name under **`/run/bare-os/ipc/`**.
|
||||
- `BARE_OS_VFS_BIN_CACHE` — VFS — When **`1`** / **`true`**, LRU read cache for **`/bin`**; invalidated on **`vfs.watch`** when enabled.
|
||||
- `BARE_OS_VFS_BIN_CACHE_BLAKE2B` — VFS — When **`1`** / **`true`** with **`BARE_OS_VFS_BIN_CACHE`**, **`/bin`** cache entries are keyed by **BLAKE2b** content digests (via **`bare-crypto`**) for deduplication across paths within the LRU budget.
|
||||
- `BARE_OS_VFS_ENFORCE_ACL` — VFS — When **`1`** / **`true`**, optional **`/.bare_acl`** sidecars can deny reads/writes on the personal drive (see **`bare-os-vfs-acl-enforce.js`**).
|
||||
- `BARE_OS_VFS_BIN_INDEX_BUILD` — Booter — When **`1`** / **`true`**, writes **`/.bare-os/index/bin-manifest.json`** on the personal drive for large images (see **`bare-os-bin-index.js`**).
|
||||
- `BARE_OS_BOOT_MANIFEST` — Stock kernel — Enable digest check of **`/etc/bare-os/boot.manifest.json`**.
|
||||
- `BARE_OS_BOOT_MANIFEST_SIGN` — Stock kernel + booter — When **`1`**, require valid Ed25519 signature file **`/etc/bare-os/boot.manifest.sig`** (see **`BARE_OS_BOOT_MANIFEST_PUBKEY_HEX`**).
|
||||
- `BARE_OS_BOOT_MANIFEST_PUBKEY_HEX` — Booter / kernel — 64 hex chars — public key for signed boot manifest verification.
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Node vs Bare host matrix
|
||||
|
||||
This repository mixes **Node** (CI and some package scripts) and **Bare** / **Pear** (stock booter and seeder entrypoints). Use this table when choosing where a test or tool runs.
|
||||
|
||||
| Surface | Typical host | Notes |
|
||||
|--------|----------------|-------|
|
||||
| `packages/bare-os-booter/test.js` | **Node** + `bare-node-test-shim.cjs` | Exercises the booter with Brittle; uses Node `fs` / `path` in the harness only. |
|
||||
| `packages/bare-os-booter/test.identity.js` | **Bare** (`brittle-bare`) | Identity paths prefer Bare APIs. |
|
||||
| `packages/bare-os-protocol/test.js` | **Bare** (`brittle-bare`); optional `test:node` | Protocol encodings are runtime-agnostic. |
|
||||
| `packages/bare-os-coreutils/test/*.mjs` | **Node** | Utilities are loaded via `AsyncFunction`; stdin/fs helpers use Node in tests. |
|
||||
| `packages/bare-os-booter` `start` / `dev` | **Bare** (`bare index.js`) | Production-shaped guest path; Pear uses the same tree with staged `node_modules`. |
|
||||
| Guest **`ctx`** / **`/bin`** / kernel **`init.js`** | **Bare** (or Pear) | Must not rely on `node:*` built-ins; use **`bare-*`** shims per project rules. |
|
||||
| Repo `pretest` verify scripts | **Node** | Static analysis, schema checks, bundle policy. |
|
||||
|
||||
Root **`npm run test:bare`** runs a small Bare-first slice (protocol + coreutils Node tests are still Node; see script in root `package.json`).
|
||||
|
||||
For Holepunch alignment, compare versions against your local mirror under `holepunchto_repos` (e.g. `bare-subprocess`, `bare-hrtime`, `pear-runtime`).
|
||||
@@ -1,29 +1,20 @@
|
||||
# Vault encryption at rest — threat model (Bare OS)
|
||||
# Vault and key-rotation threat model (Bare OS)
|
||||
|
||||
This document summarizes how personal-drive vault material is expected to behave in guest and host contexts. It complements `/proc/bare_os/security_posture.json` (`vaultAtRest`, `vaultRotation`, `accountKeyRotationContinuity`).
|
||||
Bare OS keeps **Ed25519** account material sealed for the personal Hyperdrive using **`bare-crypto`** (see **`identity-session.js`**). This note is intentionally short: it records **what the guest trusts** and **what operators must still verify on the host**.
|
||||
|
||||
## Scope
|
||||
## Trust boundaries
|
||||
|
||||
- **In scope**: encryption of vault payloads at rest on replicated drives, AEAD usage, key-handle lifetimes, rotation checkpoints, and operator-supplied metadata (non-secret).
|
||||
- **Out of scope**: host disk encryption (FileVault, LUKS), Pear platform keychains unless explicitly bridged via env pointers, and side-channel analysis.
|
||||
- **Guest image (`/bin`, kernel, booter)** is assumed **integrity-checked** by your release process (manifest signing, Pear channel policy, or offline LKG keys). Compromised image ⇒ full session compromise regardless of vault design.
|
||||
- **Personal drive** is writable by the unlocked session. **`ctx.bareOsAppendVaultRotationCheckpoint`** appends **plaintext NDJSON audit rows** to **`/.bare/vault-rotation-audit.ndjson`** — useful for continuity evidence, **not** a secret store. Do not place raw private keys there.
|
||||
- **Host Corestore / filesystem** holds material the guest cannot fully audit. Treat disk encryption, backups, and multi-device signing policy as **operator responsibilities**.
|
||||
|
||||
## Threats and mitigations
|
||||
## Rotation
|
||||
|
||||
| Threat | Mitigation sketch |
|
||||
|--------|-------------------|
|
||||
| Drive snapshot exfiltration | Vault bodies use **AEAD** (e.g. AES-256-GCM or XChaCha20-Poly1305 via **bare-crypto**) with keys outside the snapshot; only ciphertext and public metadata replicate. |
|
||||
| Tampering on replication | AEAD tags reject modified ciphertext on decrypt; audit chain rows (`auditChain` in security posture) support append-only operator review. |
|
||||
| Long-lived key exposure | **Key handles** with TTL (`keyHandlePolicy` in security posture) and **rotation checkpoints** (`/run/bare-os/vault-rotation-state.json`, `/.bare/vault-rotation.json`) document handoff. |
|
||||
| Multi-device continuity | Operators may pass **`BARE_OS_ACCOUNT_KEY_ROTATION_STATE_JSON`** (non-secret JSON) so guests surface signing continuity during overlapping trust windows — not private keys. |
|
||||
| Malicious extension | Extensions run under boot policy and optional **capability tokens**; vault APIs must not log or persist raw key material. |
|
||||
- **`BARE_OS_ACCOUNT_KEY_ROTATION_STATE_JSON`** (env) may describe overlapping validity windows for signing keys. Checkpoints on disk should list **which key** signed **which artifact** and **when**, so rollback does not silently accept stale trust.
|
||||
|
||||
## Operator responsibilities
|
||||
## Operational guidance
|
||||
|
||||
- Supply secure random nonces per AEAD seal where the API requires caller-provided nonces.
|
||||
- Mirror rotation checkpoints to durable storage outside the guest when recovering from total loss.
|
||||
- Treat **`BARE_OS_PEAR_SECURE_ENCLAVE_JSON`** as an opaque host capability pointer — the guest must never assume hardware backing without host attestation policy.
|
||||
- Prefer **short-lived** guest-visible hints over long-lived secrets in proc or env.
|
||||
- When experimenting with **`BARE_OS_VFS_ENFORCE_ACL`**, remember ACL sidecars are **metadata**, not a hardware root of trust.
|
||||
|
||||
## References
|
||||
|
||||
- `packages/bare-os-booter/index.js` — `procBareOsSecurityPostureText`
|
||||
- `docs/reference/kernel-security-subsystems.md` — identity and audit overview
|
||||
See also: [environment appendix](environment-and-posix-appendix.md), [handbook ch.4 — booter runtime](../../handbook/04-the-booter-runtime.md).
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"type": "object",
|
||||
"required": ["schemaVersion", "ops"],
|
||||
"properties": {
|
||||
"schemaVersion": { "type": "integer", "const": 3 },
|
||||
"schemaVersion": { "type": "integer", "const": 4 },
|
||||
"ctxApiVersion": { "type": "string" },
|
||||
"posixProfile": {
|
||||
"type": "object",
|
||||
@@ -41,6 +41,30 @@
|
||||
"type": "object",
|
||||
"additionalProperties": { "type": "integer" }
|
||||
},
|
||||
"fdModel": {
|
||||
"type": "object",
|
||||
"description": "Logical FD table contract (guest); see process_table.json",
|
||||
"properties": {
|
||||
"schema": { "type": "integer" },
|
||||
"note": { "type": "string" },
|
||||
"stdio": { "type": "array", "items": { "type": "integer" } },
|
||||
"register": { "type": "string" },
|
||||
"processTablePath": { "type": "string" },
|
||||
"processTableSchema": { "type": "integer" }
|
||||
}
|
||||
},
|
||||
"signalModel": {
|
||||
"type": "object",
|
||||
"description": "Synthetic signal names for ctx.bareOsSendSignal",
|
||||
"properties": {
|
||||
"schema": { "type": "integer" },
|
||||
"note": { "type": "string" },
|
||||
"names": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"caps": { "type": "object" },
|
||||
"atMs": { "type": "integer" }
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ If you come from Linux or macOS, Bare OS **feels** like a small Unix: **`ls`**,
|
||||
|
||||
**Normative reference:** Open Group **Issue 7** — use the online utilities index for intended semantics; Bare behavior may intentionally diverge where Hyperdrive or the single-process runtime makes full compliance impossible.
|
||||
|
||||
**Declared profile:** 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 **3** for that file; **`/proc/bare_os/index.json`** uses schema **8**). 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:** 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 **4** for that file — **`fdModel`** / **`signalModel`** plus earlier **`opsDetail`** / **`errnoHints`**; **`/proc/bare_os/index.json`** uses schema **8**). 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -70,7 +70,7 @@ Hyperdrive does not always behave like a POSIX directory tree. Empty directories
|
||||
|
||||
### 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 (see [Chapter 4](04-the-booter-runtime.md)). Other pseudo **`writeFile`** / **`unlink`** / **`chmod`** paths fail as documented there. Extra Linux-shaped stubs include **`/proc/cpuinfo`**, **`/proc/meminfo`**, **`/proc/loadavg`**, **`/proc/net/dev`**, **`/proc/net/tcp`**, **`/proc/net/udp`**, **`/proc/diskstats`**, **`/proc/bare_os/`** (stable aliases + **`index.json`** schema **8**, listing Pear/Bare operator JSON from Capability words 6–11 such as **`pear_stage_pointer.json`**, **`bare_module_resolution.json`**, **`pear_doctor_state.json`**, **`bare_boot_phase_map.json`**, …, plus **`syscalls.json`**, **`process_table.json`**, **`metrics.prom`**, **`protomux.json`**), **`/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 (see [Chapter 4](04-the-booter-runtime.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 6–11 such as **`pear_stage_pointer.json`**, **`bare_module_resolution.json`**, **`pear_doctor_state.json`**, **`bare_boot_phase_map.json`**, …, plus **`syscalls.json`**, **`process_table.json`**, **`metrics.prom`**, **`protomux.json`**), **`/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`**.
|
||||
|
||||
### 2.4 `chmod` (octal and symbolic)
|
||||
@@ -82,7 +82,11 @@ Hyperdrive does not always behave like a POSIX directory tree. Empty directories
|
||||
|
||||
**`/bin/chown`** and **`/bin/chgrp`** update **`metadata.bareOs`** on the **personal** drive via **`vfs.chown`** (same writable scope as **`chmod`**); root vs owner rules apply, but this is still a single-session runtime (not a multi-user host kernel).
|
||||
|
||||
### 2.5 Copy and move
|
||||
### 2.5 Auxiliary read-only drives (`/mirror`)
|
||||
|
||||
When HDMS or the booter attaches extra Hyperdrives on **`disk.auxiliaryDrives`**, the VFS exposes them read-only under **`/mirror/aux0`**, **`/mirror/aux1`**, … (also listed in **`/proc/mounts`**). This is optional; most images omit auxiliary drives.
|
||||
|
||||
### 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).
|
||||
- **`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`**).
|
||||
@@ -113,7 +117,7 @@ flowchart LR
|
||||
|
||||
**Top-level syntax:** the line is split on **`;`** into separate lists (semicolons **inside** compound blocks do not end the outer statement). **`if`** **`then`** **[** **`else`** **]** **`fi`** uses the same **`&&`** / **`||`** / pipeline rules inside the condition and each branch; the condition is true when the last evaluated command in that **`&&`/`||`** list exits **0**. **`while`** **`list;`** **`do`** **`list;`** **`done`** and **`for`** **`name`** **`in`** **words** **`;`** **`do`** **`list;`** **`done`** repeat the body while respecting **`BARE_OS_SHELL_LOOP_MAX`**. **`case`** **`word`** **`in`** **`pattern)`** **`list`** **`;;`** … **`esac`** matches the first pattern (token-safe); patterns support **`|`** alternation and fnmatch-style **`*`**, **`?`**, and **`[…]`** (excluding **`|`** branches handled separately). Branch count is capped by **`BARE_OS_SHELL_CASE_MAX_BRANCHES`**. Each list is an **AND-OR** chain: **pipelines** separated by **`&&`** or **`||`**, evaluated left-to-right with POSIX-style short-circuiting (**`ctx.exitCode`** — treat missing as **0**). Within a pipeline, **`|`** connects stages as before (simulated stdin between utilities).
|
||||
|
||||
**Background / jobs (subset):** a trailing **`&`** on a top-level list runs that list asynchronously (microtask). **`jobs`** lists recent jobs; **`fg`** awaits the selected (or latest) job; **`wait`** awaits one job by id (or **`%id`**) or all background jobs; **`bg`** is a stub (no stopped-job resume). This is **not** POSIX job control (no real processes or signals).
|
||||
**Background / jobs (subset):** a trailing **`&`** on a top-level list runs that list asynchronously (microtask). **`jobs`** lists recent jobs (including **Stopped** when **`suspend-job`** was used); **`fg`** awaits the selected (or latest) job; **`wait`** awaits one job by id (or **`%id`**) or all background jobs; **`bg`** clears **Stopped** and re-queues the job (logical resume within the single-session runtime). **`trap -l`** / **`trap -p`** / **`trap CMD SIG`** use **`ctx.shellTrapHandlers`** (delivery still maps through **`ctx.bareOsSendSignal`** for synthetic PIDs). This is **not** full POSIX job control (no host **`fork`** or kernel signals).
|
||||
|
||||
**Here-string / here-document:** **`<<< word`** feeds the expanded **word** as stdin to the first command in the pipeline. A line that **ends** with **`<<`** **`DELIMITER`** (optional **`'...'`** / **`"..."`** around the delimiter) collects following lines from **`readLine('> ')`** until a line equals **DELIMITER**, then uses that body as stdin (**`$`** expansion is skipped for a single-quoted delimiter name).
|
||||
|
||||
|
||||
@@ -121,6 +121,22 @@ async function run(ctx, argv) {
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
const rbuf = await ctx.vfs.readFile('/proc/bare_os_resources')
|
||||
if (rbuf) {
|
||||
const j = JSON.parse(ctx.b4a.toString(rbuf))
|
||||
const sv = j && j.statvfs
|
||||
if (sv && typeof sv.f_blocks === 'number' && typeof sv.f_bfree === 'number') {
|
||||
const bsize = typeof sv.f_bsize === 'number' ? sv.f_bsize : 4096
|
||||
totalK = Math.max(1024, Math.ceil((sv.f_blocks * bsize) / 1024))
|
||||
const freeB = sv.f_bavail ?? sv.f_bfree
|
||||
const freeKFromStat = Math.max(0, Math.ceil((freeB * bsize) / 1024))
|
||||
usedK = Math.max(0, totalK - freeKFromStat)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
const freeK = Math.max(0, totalK - usedK)
|
||||
const pct =
|
||||
totalK > 0 ? Math.min(100, Math.round((usedK / totalK) * 100)) : 0
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ async function run(ctx, argv) {
|
||||
break
|
||||
}
|
||||
if (a === '-l' || a === '--list') {
|
||||
ctx.console.log('HUP INT KILL TERM 0')
|
||||
ctx.console.log('HUP INT KILL TERM PIPE CHLD USR1 USR2 0')
|
||||
return
|
||||
}
|
||||
if (a === '-s' || a === '--signal') {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 3,
|
||||
"ctxApiVersion": "1.30.0",
|
||||
"schemaVersion": 4,
|
||||
"ctxApiVersion": "1.31.0",
|
||||
"posixProfile": {
|
||||
"id": "bare-os-posix-like",
|
||||
"version": "1.0.0"
|
||||
@@ -14,6 +14,19 @@
|
||||
"ENOENT": 2,
|
||||
"EACCES": 13
|
||||
},
|
||||
"fdModel": {
|
||||
"schema": 1,
|
||||
"note": "Integer FDs index logical VFS/IPC targets in the guest.",
|
||||
"stdio": [0, 1, 2],
|
||||
"register": "ctx.bareOsRegisterLogicalFd",
|
||||
"processTablePath": "/proc/bare_os/process_table.json",
|
||||
"processTableSchema": 3
|
||||
},
|
||||
"signalModel": {
|
||||
"schema": 1,
|
||||
"note": "ctx.bareOsSendSignal delivers to synthetic pids.",
|
||||
"names": ["HUP", "INT", "KILL", "TERM"]
|
||||
},
|
||||
"caps": {
|
||||
"note": "example"
|
||||
},
|
||||
|
||||
+202
-202
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"version": 1,
|
||||
"bundles": [
|
||||
{
|
||||
"path": "/lib/bare/bundles/b4a.js",
|
||||
"keys": [
|
||||
"b4a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/safetyCatch.js",
|
||||
"keys": [
|
||||
"safetyCatch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/b4a.js",
|
||||
"keys": [
|
||||
"b4a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
|
||||
"keys": [
|
||||
@@ -25,18 +25,18 @@
|
||||
"compactEncoding"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/protomux.js",
|
||||
"keys": [
|
||||
"protomux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUrl.js",
|
||||
"keys": [
|
||||
"bareUrl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/protomux.js",
|
||||
"keys": [
|
||||
"protomux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePath.js",
|
||||
"keys": [
|
||||
@@ -61,12 +61,6 @@
|
||||
"bareAbort"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAnsiEscapes.js",
|
||||
"keys": [
|
||||
"bareAnsiEscapes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAbortController.js",
|
||||
"keys": [
|
||||
@@ -79,6 +73,12 @@
|
||||
"bareReadline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAnsiEscapes.js",
|
||||
"keys": [
|
||||
"bareAnsiEscapes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAddonResolve.js",
|
||||
"keys": [
|
||||
@@ -97,6 +97,12 @@
|
||||
"bareAppKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/fetch.js",
|
||||
"keys": [
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAsyncHooks.js",
|
||||
"keys": [
|
||||
@@ -121,36 +127,24 @@
|
||||
"bareAtomics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/fetch.js",
|
||||
"keys": [
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBmp.js",
|
||||
"keys": [
|
||||
"bareBmp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundle.js",
|
||||
"keys": [
|
||||
"bareBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleCompile.js",
|
||||
"keys": [
|
||||
"bareBundleCompile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBuffer.js",
|
||||
"keys": [
|
||||
"bareBuffer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleCompile.js",
|
||||
"keys": [
|
||||
"bareBundleCompile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBluetoothApple.js",
|
||||
"keys": [
|
||||
@@ -158,9 +152,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleEvaluate.js",
|
||||
"path": "/lib/bare/bundles/bareBundle.js",
|
||||
"keys": [
|
||||
"bareBundleEvaluate"
|
||||
"bareBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -170,9 +164,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareConsole.js",
|
||||
"path": "/lib/bare/bundles/bareBundleEvaluate.js",
|
||||
"keys": [
|
||||
"bareConsole"
|
||||
"bareBundleEvaluate"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -188,9 +182,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDelta.js",
|
||||
"path": "/lib/bare/bundles/bareConsole.js",
|
||||
"keys": [
|
||||
"bareDelta"
|
||||
"bareConsole"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -206,15 +200,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDiagnosticsChannel.js",
|
||||
"path": "/lib/bare/bundles/bareDelta.js",
|
||||
"keys": [
|
||||
"bareDiagnosticsChannel"
|
||||
"bareDelta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDns.js",
|
||||
"path": "/lib/bare/bundles/bareDiagnosticsChannel.js",
|
||||
"keys": [
|
||||
"bareDns"
|
||||
"bareDiagnosticsChannel"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -224,9 +218,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareExif.js",
|
||||
"path": "/lib/bare/bundles/bareDns.js",
|
||||
"keys": [
|
||||
"bareExif"
|
||||
"bareDns"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -235,42 +229,36 @@
|
||||
"bareDgram"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpeg.js",
|
||||
"keys": [
|
||||
"bareFfmpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareCov.js",
|
||||
"keys": [
|
||||
"bareCov"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareExif.js",
|
||||
"keys": [
|
||||
"bareExif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
|
||||
"keys": [
|
||||
"bareFfmpegEncodings"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpeg.js",
|
||||
"keys": [
|
||||
"bareFfmpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFormat.js",
|
||||
"keys": [
|
||||
"bareFormat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareGif.js",
|
||||
"keys": [
|
||||
"bareGif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFormData.js",
|
||||
"keys": [
|
||||
"bareFormData"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFileLogger.js",
|
||||
"keys": [
|
||||
@@ -278,21 +266,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFs.js",
|
||||
"path": "/lib/bare/bundles/bareFormData.js",
|
||||
"keys": [
|
||||
"bareFs"
|
||||
"bareFormData"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttpParser.js",
|
||||
"path": "/lib/bare/bundles/bareGif.js",
|
||||
"keys": [
|
||||
"bareHttpParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHeif.js",
|
||||
"keys": [
|
||||
"bareHeif"
|
||||
"bareGif"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -301,12 +283,24 @@
|
||||
"bareGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHeif.js",
|
||||
"keys": [
|
||||
"bareHeif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHrtime.js",
|
||||
"keys": [
|
||||
"bareHrtime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttpParser.js",
|
||||
"keys": [
|
||||
"bareHttpParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIco.js",
|
||||
"keys": [
|
||||
@@ -320,9 +314,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareInspect.js",
|
||||
"path": "/lib/bare/bundles/bareFs.js",
|
||||
"keys": [
|
||||
"bareInspect"
|
||||
"bareFs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -332,21 +326,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttps.js",
|
||||
"path": "/lib/bare/bundles/bareInspect.js",
|
||||
"keys": [
|
||||
"bareHttps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"keys": [
|
||||
"bareJpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIpc.js",
|
||||
"keys": [
|
||||
"bareIpc"
|
||||
"bareInspect"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -356,15 +338,27 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLogger.js",
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"keys": [
|
||||
"bareLogger"
|
||||
"bareJpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLief.js",
|
||||
"path": "/lib/bare/bundles/bareHttps.js",
|
||||
"keys": [
|
||||
"bareLief"
|
||||
"bareHttps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIpc.js",
|
||||
"keys": [
|
||||
"bareIpc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLogger.js",
|
||||
"keys": [
|
||||
"bareLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -373,12 +367,6 @@
|
||||
"bareInspector"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"keys": [
|
||||
"bareMake"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLink.js",
|
||||
"keys": [
|
||||
@@ -386,9 +374,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModule.js",
|
||||
"path": "/lib/bare/bundles/bareLief.js",
|
||||
"keys": [
|
||||
"bareModule"
|
||||
"bareLief"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"keys": [
|
||||
"bareMake"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -404,9 +398,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModuleTraverse.js",
|
||||
"path": "/lib/bare/bundles/bareModule.js",
|
||||
"keys": [
|
||||
"bareModuleTraverse"
|
||||
"bareModule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"keys": [
|
||||
"bareDev"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -428,15 +428,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"path": "/lib/bare/bundles/bareModuleTraverse.js",
|
||||
"keys": [
|
||||
"bareDev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMedia.js",
|
||||
"keys": [
|
||||
"bareMedia"
|
||||
"bareModuleTraverse"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -445,6 +439,12 @@
|
||||
"bareOpen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareOs.js",
|
||||
"keys": [
|
||||
"bareOs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNet.js",
|
||||
"keys": [
|
||||
@@ -452,9 +452,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareOs.js",
|
||||
"path": "/lib/bare/bundles/bareMedia.js",
|
||||
"keys": [
|
||||
"bareOs"
|
||||
"bareMedia"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -475,18 +475,18 @@
|
||||
"barePack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePackDrive.js",
|
||||
"keys": [
|
||||
"barePackDrive"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePipe.js",
|
||||
"keys": [
|
||||
"barePipe"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePackDrive.js",
|
||||
"keys": [
|
||||
"barePackDrive"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePunycode.js",
|
||||
"keys": [
|
||||
@@ -499,24 +499,18 @@
|
||||
"barePrebuild"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQuerystring.js",
|
||||
"keys": [
|
||||
"bareQuerystring"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"keys": [
|
||||
"bareProcess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNodeRuntime.js",
|
||||
"keys": [
|
||||
"bareNodeRuntime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQuerystring.js",
|
||||
"keys": [
|
||||
"bareQuerystring"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
|
||||
"keys": [
|
||||
@@ -529,6 +523,12 @@
|
||||
"bareRealm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"keys": [
|
||||
"bareProcess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRuntime.js",
|
||||
"keys": [
|
||||
@@ -542,9 +542,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSemver.js",
|
||||
"path": "/lib/bare/bundles/bareSdl.js",
|
||||
"keys": [
|
||||
"bareSemver"
|
||||
"bareSdl"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -554,15 +554,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSdl.js",
|
||||
"path": "/lib/bare/bundles/bareSemver.js",
|
||||
"keys": [
|
||||
"bareSdl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSidecar.js",
|
||||
"keys": [
|
||||
"bareSidecar"
|
||||
"bareSemver"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -572,9 +566,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRepl.js",
|
||||
"path": "/lib/bare/bundles/bareSidecar.js",
|
||||
"keys": [
|
||||
"bareRepl"
|
||||
"bareSidecar"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -590,9 +584,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStream.js",
|
||||
"path": "/lib/bare/bundles/bareRepl.js",
|
||||
"keys": [
|
||||
"bareStream"
|
||||
"bareRepl"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -601,6 +595,12 @@
|
||||
"bareStorage"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStream.js",
|
||||
"keys": [
|
||||
"bareStream"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStdio.js",
|
||||
"keys": [
|
||||
@@ -620,15 +620,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSubprocess.js",
|
||||
"path": "/lib/bare/bundles/bareTiff.js",
|
||||
"keys": [
|
||||
"bareSubprocess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSystemLogger.js",
|
||||
"keys": [
|
||||
"bareSystemLogger"
|
||||
"bareTiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -638,21 +632,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTiff.js",
|
||||
"path": "/lib/bare/bundles/bareSystemLogger.js",
|
||||
"keys": [
|
||||
"bareTiff"
|
||||
"bareSystemLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTimers.js",
|
||||
"path": "/lib/bare/bundles/bareSubprocess.js",
|
||||
"keys": [
|
||||
"bareTimers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTpl.js",
|
||||
"keys": [
|
||||
"bareTpl"
|
||||
"bareSubprocess"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -661,6 +649,12 @@
|
||||
"bareThread"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTimers.js",
|
||||
"keys": [
|
||||
"bareTimers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTcp.js",
|
||||
"keys": [
|
||||
@@ -668,9 +662,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareType.js",
|
||||
"path": "/lib/bare/bundles/bareTpl.js",
|
||||
"keys": [
|
||||
"bareType"
|
||||
"bareTpl"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -679,12 +673,24 @@
|
||||
"bareTls"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareType.js",
|
||||
"keys": [
|
||||
"bareType"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUiKit.js",
|
||||
"keys": [
|
||||
"bareUiKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTty.js",
|
||||
"keys": [
|
||||
"bareTty"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnpack.js",
|
||||
"keys": [
|
||||
@@ -697,24 +703,6 @@
|
||||
"bareV8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTty.js",
|
||||
"keys": [
|
||||
"bareTty"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKit.js",
|
||||
"keys": [
|
||||
"bareWebKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareVm.js",
|
||||
"keys": [
|
||||
"bareVm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnionBundle.js",
|
||||
"keys": [
|
||||
@@ -727,6 +715,18 @@
|
||||
"bareWalkHandles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareVm.js",
|
||||
"keys": [
|
||||
"bareVm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKit.js",
|
||||
"keys": [
|
||||
"bareWebKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebp.js",
|
||||
"keys": [
|
||||
@@ -734,15 +734,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWhich.js",
|
||||
"path": "/lib/bare/bundles/bareWebKitGtk.js",
|
||||
"keys": [
|
||||
"bareWhich"
|
||||
"bareWebKitGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"path": "/lib/bare/bundles/bareWhich.js",
|
||||
"keys": [
|
||||
"bareV8ToIstanbul"
|
||||
"bareWhich"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -758,15 +758,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKitGtk.js",
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"keys": [
|
||||
"bareWebKitGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareXdiff.js",
|
||||
"keys": [
|
||||
"bareXdiff"
|
||||
"bareV8ToIstanbul"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -782,9 +776,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWorker.js",
|
||||
"path": "/lib/bare/bundles/bareXdiff.js",
|
||||
"keys": [
|
||||
"bareWorker"
|
||||
"bareXdiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -792,6 +786,12 @@
|
||||
"keys": [
|
||||
"bareWs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWorker.js",
|
||||
"keys": [
|
||||
"bareWorker"
|
||||
]
|
||||
}
|
||||
],
|
||||
"bundleStats": {
|
||||
@@ -1595,8 +1595,8 @@
|
||||
],
|
||||
"bundleProvenance": {
|
||||
"schemaVersion": 1,
|
||||
"generatedAt": "2026-04-05T01:31:52.568Z",
|
||||
"gitCommit": "346bb71ffe4b7d059d4e16454dc9e4afff73224b",
|
||||
"generatedAt": "2026-04-05T01:58:32.340Z",
|
||||
"gitCommit": "57ba71899bdfadc92caeb9eb8ede55d3484d9697",
|
||||
"nodeVersion": "v22.22.0",
|
||||
"bundleTier": "all",
|
||||
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"atMs": 1775352711830,
|
||||
"atMs": 1775354354273,
|
||||
"commands": [
|
||||
"arch",
|
||||
"awk",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -17,6 +17,7 @@
|
||||
"bundle:kernel": "node scripts/bundle-kernel-init.mjs",
|
||||
"pretest": "npm run build -w bare-os-coreutils && npm run build -w bare-os-bare-libs && npm run bundle:kernel && node scripts/gen-kernel-extensions-index.mjs && node scripts/verify-kernel-seeder-parity.mjs && node scripts/verify-banned-terminology.mjs && node scripts/verify-naming-alias-matrix.mjs && node scripts/verify-feature-roadmap-canonical.mjs && node scripts/verify-no-new-giant-phase-identifiers.mjs && node scripts/verify-runtime-no-incomplete-markers.mjs && node scripts/verify-bare-imports.mjs && node scripts/verify-booter-boot-steps-alignment.mjs && node scripts/gen-ctx-client-helper.mjs && node scripts/verify-extension-manifest-schema.mjs && node scripts/verify-ctx-api-feature-bits.mjs && node scripts/verify-kernel-capabilities-contract.mjs && node scripts/verify-kernel-capabilities-word-6.mjs && node scripts/verify-kernel-capabilities-word-7.mjs && node scripts/verify-kernel-capabilities-word-8.mjs && node scripts/verify-kernel-capabilities-word-9.mjs && node scripts/verify-kernel-capabilities-word-10.mjs && node scripts/verify-kernel-capabilities-word-11.mjs && node scripts/verify-ctx-dts.mjs && node scripts/validate-example-schemas.mjs && node scripts/verify-doc-links.mjs && node scripts/verify-man-coverage.mjs && node scripts/verify-compat-matrix.mjs && node scripts/verify-bundle-health.mjs && node scripts/verify-bundle-markers.mjs && node scripts/verify-bundle-throws.mjs && node scripts/verify-kernel-program-doc.mjs && node scripts/verify-kernel-program-proc-schema.mjs && node scripts/verify-kernel-program-roadmap-table.mjs && node scripts/verify-pear-no-static-node-import.mjs && npm run smoke:bare-manifest",
|
||||
"test": "npm run test --workspaces --if-present",
|
||||
"test:bare": "npm run test -w bare-os-protocol && npm run test:bare -w bare-os-booter && npm run test -w bare-os-seeder",
|
||||
"verify-kernel-seeder": "node scripts/verify-kernel-seeder-parity.mjs",
|
||||
"release-checklist": "node scripts/release-checklist.mjs",
|
||||
"format": "prettier --write .",
|
||||
|
||||
@@ -4,7 +4,7 @@ Authoritative **version alignment** with protocol and telemetry schema numbers l
|
||||
|
||||
## Maintenance
|
||||
|
||||
- **POSIX / proc**: **`/proc/bare_os/syscalls.json`** schema **3** (**`opsDetail`**, errno map via **`bare-os-posix-errno.js`**, **`posixProfile`**); **`/proc/bare_os_features`** includes **`capabilitySurface`** (feature words + POSIX profile summary); **`/proc/bare_os_swarm`** embeds **`timeSync`** sketch; **`/proc/bare_os/process_table.json`** schema **2** (session, rlimits, fd summary, job zombies). Protocol export **`BARE_OS_POSIX_PROFILE_*`**.
|
||||
- **POSIX / proc**: **`/proc/bare_os/syscalls.json`** schema **4** adds **`fdModel`** / **`signalModel`** (plus schema **3** **`opsDetail`**, errno map, **`posixProfile`**); **`/proc/bare_os_features`** includes **`capabilitySurface`**; **`/proc/bare_os_swarm`** embeds **`timeSync`** sketch; **`/proc/bare_os/process_table.json`** schema **3** (session, rlimits, logical FD rows, job **`stopped`**, **`signalModel`**). Protocol export **`BARE_OS_POSIX_PROFILE_*`**.
|
||||
- **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).
|
||||
- **Pear / Bare**: [`lib/kernel-runner.js`](lib/kernel-runner.js) must not **static**-import **`node:module`** (Bare’s 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.
|
||||
@@ -14,6 +14,7 @@ Authoritative **version alignment** with protocol and telemetry schema numbers l
|
||||
|
||||
| Version | Booter (workspace) | Notes |
|
||||
| ------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| 1.31.0 | 0.1.0 | **`/proc/bare_os/syscalls.json`** schema **4** (**`fdModel`**, **`signalModel`**). **`ctx`**: **`bareOsRegisterLogicalFd`**, **`bareOsTrySpawnHostSubprocess`**, **`bareOsAppendVaultRotationCheckpoint`**, **`shellTrapHandlers`**. VFS: read-only **`/mirror/aux0`…** for **`disk.auxiliaryDrives`**; optional **`BARE_OS_VFS_BIN_CACHE_BLAKE2B`** (BLAKE2b-keyed **`/bin`** cache when **`bare-crypto`** loads). Passthrough env: **`BARE_OS_VFS_ENFORCE_ACL`**, **`BARE_OS_VFS_BIN_INDEX_BUILD`**. Seeder wires **`snapshotHintsJson`** from **`BARE_OS_SEED_SNAPSHOT_HINTS_JSON`** or **`BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG`**. |
|
||||
| 1.28.0 | 0.1.0 | **`ctx.bareOsRunSystemctlCli`**: drive-resident **`systemctl`** / **`journalctl`** call the same backend as host delegates when the booter exposes this method. **`disk.os`**: **`createBareOsDiskOsBridge`** — Hyperdrive path **`searchLocal`**, whitelisted **`bare_os.*`** **`execRpc`** (typed **`BareOsKernelError`** on unknown). Host delegates: **`warc`** (WARC 1.0 list/write-response), **`archive`** (ustar tar front-end); **`ssh-keygen`** passphrase → **`bareOsKeySchema: 2`** (PBKDF2 + ChaCha20-Poly1305). New **`lib/bare-os-boot-phases.js`**, **`lib/bare-os-errors.js`**. CI: **`verify-booter-boot-steps-alignment.mjs`**. Docs: **`docs/architecture/KERNEL_CONTRACT.md`**, **`docs/deployment/OTA_AND_BUNDLES.md`**, **`docs/audit/PLACEHOLDER_BASELINE.md`**, handbook §3 **`disk.os`**. |
|
||||
| 1.25.0 | 0.1.0 | Kernel program proc: primary **`/proc/bare_os/kernel_program.json`** + proc id **`kernel_program`** (legacy **`giant_phase_program`** unchanged); JSON uses **`operatorSketches`** and **`program: bare-os-kernel-program`**; env **`BARE_OS_KERNEL_PROGRAM_PROC_JSON`** (legacy **`BARE_OS_GIANT_PHASE_PROGRAM_JSON`**); **`subsystems.kernel.programProc`** on **`bareOsPublishBootReady`** (replaces **`giantPhase`**). CI: **`verify-kernel-program-doc.mjs`**, **`verify-kernel-program-proc-schema.mjs`**, **`verify-kernel-program-roadmap-table.mjs`**. Module **`bare-os-giant-phase.js`** removed in favor of **`bare-os-kernel-program-proc.js`**. |
|
||||
| 1.24.0 | 0.1.0 | **`bareOsEmitKernelEvent`** / **`bareOsSubscribeKernelEvent`**, **`bareOsAcquireKeyHandle`** sketch; **`/run/bare-os/services.json`** seed; optional **`BARE_OS_LOADER_AUDIT`** → **`loader-audit.ndjson`**; proc **schema 2** + operator env sketches (historically documented as giant-phase / **`gp2`**); runtime caps **`kernelEventSubscribe`**, **`keyBrokerHandleSketch`**. Stock kernel: boot stages, dry-run, policy fallbacks, ABI min, services registry consumers. |
|
||||
|
||||
@@ -103,7 +103,8 @@ import {
|
||||
unlockIdentity,
|
||||
logoutIdentity,
|
||||
saveVaultToDrive,
|
||||
applyLoginKeys
|
||||
applyLoginKeys,
|
||||
bareOsAppendVaultRotationCheckpoint
|
||||
} from './lib/identity-session.js'
|
||||
import { HdmsController, runHdmsCli } from './lib/hdms-manager.js'
|
||||
import {
|
||||
@@ -180,6 +181,8 @@ import {
|
||||
import { bareOsSwarmLifecycleSnapshot } from './lib/bare-os-swarm-lifecycle.js'
|
||||
import { bareOsReadHostProfile } from './lib/bare-os-host-profile.js'
|
||||
import { bareOsProcessTableSnapshot } from './lib/bare-os-process-table.js'
|
||||
import { bareOsStatvfsFromHyperdrive } from './lib/bare-os-statvfs-from-drive.js'
|
||||
import { maybeBareOsBuildBinManifest } from './lib/bare-os-bin-index.js'
|
||||
import { BARE_OS_ACCOUNT_CRYPTO_PROFILE_V2 } from './lib/identity-account.js'
|
||||
import { evaluateBareOsPeerAdmission } from './lib/bare-os-peer-admission.js'
|
||||
import { prioritizeReplicationPaths } from './lib/bare-os-replication-priority.js'
|
||||
@@ -516,6 +519,9 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
'BARE_OS_URANDOM_CRYPTO',
|
||||
'BARE_OS_INITD_MAX_PARALLEL',
|
||||
'BARE_OS_VFS_BIN_CACHE',
|
||||
'BARE_OS_VFS_BIN_CACHE_BLAKE2B',
|
||||
'BARE_OS_VFS_ENFORCE_ACL',
|
||||
'BARE_OS_VFS_BIN_INDEX_BUILD',
|
||||
'BARE_OS_SANDBOX_WORKER',
|
||||
'BARE_OS_BLIND_BOOTSTRAP_URL',
|
||||
'BARE_OS_BLIND_BOOTSTRAP_JSON',
|
||||
@@ -664,6 +670,15 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
/** @type {Set<(ev: Record<string, unknown>) => void | Promise<void>>} */
|
||||
const eventBusSubs = new Set()
|
||||
const bootStartedMs = Date.now()
|
||||
/** @type {null | (() => bigint)} */
|
||||
let bootHrtimeNowNs = null
|
||||
try {
|
||||
const bh = await import('bare-hrtime')
|
||||
const hr = bh?.hrtime
|
||||
if (hr && typeof hr.bigint === 'function') bootHrtimeNowNs = () => hr.bigint()
|
||||
} catch {
|
||||
/* optional native clock */
|
||||
}
|
||||
/** @type {{ ready: boolean, phases: string[], stages: string[], steps?: string[], bootStepsFlat?: string[], booterPhases: string[], booterStages: string[], sessionId: string, completedAtMs: number | null, minimal: boolean, imageDigest: string, pearChannel: string, pearRelease: string, bootProvenance?: Record<string, unknown>, subsystems?: Record<string, unknown>, bareModuleLockWarnings?: string[] }} */
|
||||
const bootReadyStateRef = {
|
||||
ready: false,
|
||||
@@ -687,7 +702,8 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
policyDigestSketch: String(
|
||||
shellEnv.BARE_OS_BOOT_POLICY_DIGEST_SKETCH || ''
|
||||
).trim(),
|
||||
bootStartedMs
|
||||
bootStartedMs,
|
||||
hrtimeAvailable: !!bootHrtimeNowNs
|
||||
},
|
||||
subsystems: {},
|
||||
bareModuleLockWarnings: []
|
||||
@@ -790,7 +806,10 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
ms: Date.now() - bootStartedMs,
|
||||
ts: Date.now(),
|
||||
sessionId: bareOsSessionId,
|
||||
lifecycleSchemaVersion: BARE_OS_LIFECYCLE_SCHEMA_VERSION
|
||||
lifecycleSchemaVersion: BARE_OS_LIFECYCLE_SCHEMA_VERSION,
|
||||
...(bootHrtimeNowNs
|
||||
? { monotonicNs: String(bootHrtimeNowNs()) }
|
||||
: {})
|
||||
}
|
||||
for (const fn of bootEventSubs) {
|
||||
Promise.resolve(fn(ev)).catch(() => {})
|
||||
@@ -806,6 +825,19 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
/** @type {Record<string, unknown> | null} */
|
||||
ctx: null
|
||||
}
|
||||
function bareOsCollectLogicalFdRows() {
|
||||
const c = bareOsInteractiveCtxRef.ctx
|
||||
const o = c?.bareOsLogicalFds
|
||||
if (!o || typeof o !== 'object') return []
|
||||
return Object.keys(o)
|
||||
.filter((k) => /^[0-9]+$/.test(k) && k !== '0' && k !== '1' && k !== '2')
|
||||
.sort((a, b) => Number(a) - Number(b))
|
||||
.map((fdNum) => ({
|
||||
fd: Number(fdNum),
|
||||
target: String(/** @type {Record<string, string>} */ (o)[fdNum] ?? '')
|
||||
}))
|
||||
}
|
||||
|
||||
function bareOsLiveShellJobsAndIpcStats() {
|
||||
const live = bareOsInteractiveCtxRef.ctx
|
||||
const shellJobs =
|
||||
@@ -856,7 +888,9 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
CLOCK_BOOTTIME_RELATIVE_MS:
|
||||
bootStartedMs != null ? wallMs - bootStartedMs : null,
|
||||
CLOCK_MONOTONIC_NS_FROM_PERF: monotonicNsFromPerf,
|
||||
note: 'clock_gettime(CLOCK_REALTIME) analog; monotonic from performance.now where the host exposes it. Optional bare-hrtime can extend this surface on Bare.'
|
||||
CLOCK_MONOTONIC_NS_HRTIME:
|
||||
bootHrtimeNowNs != null ? String(bootHrtimeNowNs()) : null,
|
||||
note: 'clock_gettime(CLOCK_REALTIME) analog; monotonic from performance.now and optional bare-hrtime.bigint() when the addon loads.'
|
||||
})}\n`
|
||||
},
|
||||
getProcSelfExtraFds() {
|
||||
@@ -874,6 +908,28 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
target: String(/** @type {Record<string, string>} */ (o)[fdNum] ?? '')
|
||||
}))
|
||||
},
|
||||
getProcSyntheticLinuxCompat() {
|
||||
const peers = disk.peers ? [...disk.peers] : []
|
||||
return {
|
||||
sessionId: bareOsSessionId,
|
||||
swarmPeerCount: peers.length,
|
||||
peerIds: peers.map((p) =>
|
||||
String(
|
||||
p.id ||
|
||||
'0000000000000000000000000000000000000000000000000000000000000000'
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
getAuxiliaryMountLines() {
|
||||
const aux = disk.auxiliaryDrives || []
|
||||
return aux.map(
|
||||
(_d, i) => `bare-os-aux${i} /mirror/aux${i} hyperdrive ro 0 0`
|
||||
)
|
||||
},
|
||||
getAuxiliaryDrives() {
|
||||
return disk.auxiliaryDrives || []
|
||||
},
|
||||
procBareOsDebugText() {
|
||||
if (
|
||||
shellEnv.BARE_OS_KERNEL_DEBUG !== '1' &&
|
||||
@@ -1080,6 +1136,8 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
} else if (pwdLogical.startsWith('/var/')) {
|
||||
volumeClass = 'system'
|
||||
}
|
||||
const sysSv = bareOsStatvfsFromHyperdrive(disk.drive)
|
||||
const perSv = bareOsStatvfsFromHyperdrive(disk.personalDrive)
|
||||
return `${JSON.stringify({
|
||||
ctxApiVersion: BARE_OS_CTX_API_VERSION,
|
||||
pipeline: pl,
|
||||
@@ -1088,18 +1146,21 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
session: sessionStatsRef,
|
||||
peers: disk.peers?.size ?? 0,
|
||||
statvfs: {
|
||||
f_bsize: 4096,
|
||||
f_frsize: 4096,
|
||||
f_blocks: null,
|
||||
f_bfree: null,
|
||||
f_bavail: null,
|
||||
f_files: null,
|
||||
f_ffree: null,
|
||||
f_namemax: 255,
|
||||
schema: 2,
|
||||
f_bsize: sysSv?.f_bsize ?? 4096,
|
||||
f_frsize: sysSv?.f_frsize ?? 4096,
|
||||
f_blocks: sysSv?.f_blocks ?? null,
|
||||
f_bfree: sysSv?.f_bfree ?? null,
|
||||
f_bavail: sysSv?.f_bavail ?? null,
|
||||
f_files: sysSv?.f_files ?? null,
|
||||
f_ffree: sysSv?.f_ffree ?? null,
|
||||
f_namemax: sysSv?.f_namemax ?? 255,
|
||||
systemDrive: sysSv,
|
||||
personalDrive: perSv,
|
||||
pwd_logical: pwdLogical,
|
||||
volume_class: volumeClass,
|
||||
f_basetype: 'hyperdrive',
|
||||
note: 'Symbolic statvfs sketch; block/file counts are null until drive-specific accounting exists. volume_class maps $PWD to the VFS routing bucket (not a POSIX fsid).'
|
||||
note: 'Best-effort Hyperdrive byte accounting via core/tree probes; null fields when the drive shape is unknown. volume_class maps $PWD to the VFS routing bucket.'
|
||||
},
|
||||
mountManager: {
|
||||
schema: 1,
|
||||
@@ -1183,6 +1244,18 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
shellEnv.BARE_OS_HTTP_RUNTIME_GUEST_ONLY !== 'false',
|
||||
note: 'bare-http1 / bare-fetch load from guest bare library paths unless boot policy expands the allowlist.'
|
||||
},
|
||||
pearRuntimeHint: {
|
||||
schema: 1,
|
||||
pearChannel: String(shellEnv.BARE_OS_PEAR_CHANNEL || '').trim() || undefined,
|
||||
pearRelease: String(shellEnv.BARE_OS_PEAR_RELEASE || '').trim() || undefined,
|
||||
pearRuntimeVersion: String(
|
||||
shellEnv.BARE_OS_PEAR_RUNTIME_VERSION || ''
|
||||
).trim() || undefined,
|
||||
updaterChannel: String(
|
||||
shellEnv.BARE_OS_PEAR_UPDATER_CHANNEL || ''
|
||||
).trim() || undefined,
|
||||
note: 'OTA / Pear stage hints for operators; compare pear-runtime-updater docs on Holepunch.'
|
||||
},
|
||||
posixShellExtendedProfile: {
|
||||
schema: 1,
|
||||
envGate: 'BARE_OS_SH_EXTENDED_PROFILE',
|
||||
@@ -2023,7 +2096,8 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
bootStartedMs,
|
||||
signalState: bareOsVirtualSignalState,
|
||||
shellJobs,
|
||||
ipcStats
|
||||
ipcStats,
|
||||
logicalFdRows: bareOsCollectLogicalFdRows()
|
||||
})
|
||||
})(),
|
||||
initdReadiness: bareInitdReadinessSnapshot(),
|
||||
@@ -2051,13 +2125,14 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
bootStartedMs,
|
||||
signalState: bareOsVirtualSignalState,
|
||||
shellJobs,
|
||||
ipcStats
|
||||
ipcStats,
|
||||
logicalFdRows: bareOsCollectLogicalFdRows()
|
||||
})
|
||||
)}\n`
|
||||
},
|
||||
procBareOsSyscallsText() {
|
||||
return `${JSON.stringify({
|
||||
schemaVersion: 3,
|
||||
schemaVersion: 4,
|
||||
ctxApiVersion: BARE_OS_CTX_API_VERSION,
|
||||
posixProfile: {
|
||||
id: BARE_OS_POSIX_PROFILE_ID,
|
||||
@@ -2067,6 +2142,19 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
ops: [...BARE_OS_STOCK_SYSCALL_OPS],
|
||||
opsDetail: [...BARE_OS_SYSCALL_OPS_DETAIL],
|
||||
errnoHints: bareOsErrnoTableForProc(),
|
||||
fdModel: {
|
||||
schema: 1,
|
||||
note: 'Integer FDs index logical VFS/IPC targets in the guest; not host kernel file descriptors.',
|
||||
stdio: [0, 1, 2],
|
||||
register: 'ctx.bareOsRegisterLogicalFd',
|
||||
processTablePath: '/proc/bare_os/process_table.json',
|
||||
processTableSchema: 3
|
||||
},
|
||||
signalModel: {
|
||||
schema: 1,
|
||||
note: 'ctx.bareOsSendSignal delivers to synthetic pids 1–3; see process_table.signalModel.sigpendingAnalog.',
|
||||
names: ['HUP', 'INT', 'KILL', 'TERM', 'PIPE', 'CHLD', 'USR1', 'USR2']
|
||||
},
|
||||
caps: {
|
||||
note: 'VFS path classes and boot policy may deny individual ops at runtime.'
|
||||
},
|
||||
@@ -2088,9 +2176,24 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
},
|
||||
procBareOsProtomuxWireText() {
|
||||
const rt = protomuxAliasRegistry.snapshot()
|
||||
const peers = disk.peers ? [...disk.peers] : []
|
||||
return `${JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
ctxApiVersion: BARE_OS_CTX_API_VERSION,
|
||||
swarm: {
|
||||
schema: 1,
|
||||
peerCount: peers.length,
|
||||
topicHex: b4a.toString(topicKey(), 'hex'),
|
||||
protocol: 'bare-os-v1'
|
||||
},
|
||||
replication: {
|
||||
schema: 1,
|
||||
seedReplicationStatus:
|
||||
disk.seedReplicationStatus &&
|
||||
typeof disk.seedReplicationStatus === 'object'
|
||||
? disk.seedReplicationStatus
|
||||
: undefined
|
||||
},
|
||||
aliases: rt.aliases,
|
||||
changeLogTail: rt.changeLogTail,
|
||||
reverseIndex: rt.reverseIndex,
|
||||
@@ -2331,6 +2434,8 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
bareOsBootStartedMs: bootStartedMs,
|
||||
/** Logical open-file targets for `/proc/self/fd/*` beyond stdio (see `bareOsRegisterLogicalFd`). */
|
||||
bareOsLogicalFds: /** @type {Record<string, string>} */ ({}),
|
||||
/** Shell `trap` COMMAND → SIGNAL map (logical job control; delivery is host-specific). */
|
||||
shellTrapHandlers: Object.create(null),
|
||||
/** True when `BARE_OS_SKIP_REPL=1` — stdin is non-interactive; `readLine` yields EOF immediately after boot. */
|
||||
bareOsSkipRepl: skipInteractive,
|
||||
disk,
|
||||
@@ -2520,6 +2625,16 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
async saveVault() {
|
||||
await saveVaultToDrive(this)
|
||||
},
|
||||
/**
|
||||
* Append vault / key rotation audit metadata (plaintext NDJSON on the personal drive).
|
||||
* @param {Record<string, unknown>} row
|
||||
*/
|
||||
async bareOsAppendVaultRotationCheckpoint(row) {
|
||||
await bareOsAppendVaultRotationCheckpoint(
|
||||
this,
|
||||
row && typeof row === 'object' ? row : {}
|
||||
)
|
||||
},
|
||||
/** Populated by `loadBarerc` / first `execShellLine` (default alias table). */
|
||||
shellAliases: undefined,
|
||||
/**
|
||||
@@ -2760,7 +2875,8 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
bootStartedMs,
|
||||
signalState: bareOsVirtualSignalState,
|
||||
shellJobs,
|
||||
ipcStats
|
||||
ipcStats,
|
||||
logicalFdRows: bareOsCollectLogicalFdRows()
|
||||
})
|
||||
},
|
||||
/**
|
||||
@@ -2818,6 +2934,29 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
}
|
||||
return { ok: true, pid, signal: sig, delivered: true, atMs }
|
||||
},
|
||||
/**
|
||||
* Try to spawn a host child via **`bare-subprocess`** when the addon is available (Bare hosts).
|
||||
* @param {string[]} argv
|
||||
* @param {Record<string, unknown>} [opts]
|
||||
*/
|
||||
async bareOsTrySpawnHostSubprocess(argv, opts) {
|
||||
const av = Array.isArray(argv) ? argv.map((x) => String(x)) : []
|
||||
try {
|
||||
const mod = await import('bare-subprocess')
|
||||
const sp = mod && (mod.default || mod)
|
||||
const spawn = sp && sp.spawn
|
||||
if (typeof spawn !== 'function') {
|
||||
return { ok: false, reason: 'bare-subprocess.spawn-unavailable' }
|
||||
}
|
||||
const child = spawn(av[0] || 'bare', av.slice(1), {
|
||||
...(opts && typeof opts === 'object' ? opts : {}),
|
||||
stdio: 'pipe'
|
||||
})
|
||||
return { ok: true, child }
|
||||
} catch (e) {
|
||||
return { ok: false, reason: (e && e.message) || String(e) }
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {number} fd
|
||||
* @param {string} target
|
||||
@@ -4625,6 +4764,7 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
|
||||
await applyGuestEnv(ctx)
|
||||
await ensureGuestHome(ctx)
|
||||
await maybeBareOsBuildBinManifest(ctx)
|
||||
|
||||
const session = await createKernelReplSession({
|
||||
stdin: sessionStdin,
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Optional `/bin` manifest on the personal drive for large images (`BARE_OS_VFS_BIN_INDEX_BUILD=1`).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
*/
|
||||
export async function maybeBareOsBuildBinManifest(ctx) {
|
||||
const e = ctx.env
|
||||
if (
|
||||
e.BARE_OS_VFS_BIN_INDEX_BUILD !== '1' &&
|
||||
e.BARE_OS_VFS_BIN_INDEX_BUILD !== 'true'
|
||||
) {
|
||||
return
|
||||
}
|
||||
const vfs = ctx.vfs
|
||||
const drive = ctx.drive
|
||||
const b4 = ctx.b4a
|
||||
if (!vfs || !drive || typeof drive.readdir !== 'function' || !b4) return
|
||||
/** @type {string[]} */
|
||||
const names = []
|
||||
try {
|
||||
const stream = drive.readdir('/bin')
|
||||
for await (const n of stream) names.push(String(n))
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
names.sort()
|
||||
const body =
|
||||
JSON.stringify({
|
||||
schema: 1,
|
||||
atMs: Date.now(),
|
||||
path: '/bin',
|
||||
count: names.length,
|
||||
names: names.slice(0, 8000)
|
||||
}) + '\n'
|
||||
try {
|
||||
await vfs.writeFile('/.bare-os/index/bin-manifest.json', b4.from(body))
|
||||
} catch (err) {
|
||||
ctx.console?.error?.(
|
||||
'[bare-os] bin index: ' + ((err && err.message) || String(err))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,4 @@
|
||||
* Semantic version of the booter `ctx` contract for custom kernels.
|
||||
* Bump when adding/removing/renaming documented `ctx` fields or changing behavior.
|
||||
*/
|
||||
export const BARE_OS_CTX_API_VERSION = '1.30.0'
|
||||
export const BARE_OS_CTX_API_VERSION = '1.31.0'
|
||||
|
||||
+16
@@ -330,6 +330,22 @@ export interface BareOsKernelContext {
|
||||
exists?: boolean
|
||||
atMs?: number
|
||||
}
|
||||
/** FD → logical VFS/IPC target; see `/proc/bare_os/syscalls.json` fdModel. */
|
||||
bareOsLogicalFds?: Record<string, string>
|
||||
/** Shell `trap` COMMAND → SIGNAL map (logical; delivery is synthetic). */
|
||||
shellTrapHandlers?: Record<string, string>
|
||||
bareOsAppendVaultRotationCheckpoint?(
|
||||
row: Record<string, unknown>
|
||||
): Promise<void>
|
||||
bareOsTrySpawnHostSubprocess?(
|
||||
argv: string[],
|
||||
opts?: Record<string, unknown>
|
||||
): Promise<
|
||||
| { ok: true; child: unknown }
|
||||
| { ok: false; reason: string }
|
||||
>
|
||||
bareOsRegisterLogicalFd?(fd: number, target: string): void
|
||||
bareOsUnregisterLogicalFd?(fd: number): void
|
||||
bareOsPathconf?(path: string, name: string): number
|
||||
bareOsSyscall?(
|
||||
op: string,
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
* sessionId?: string,
|
||||
* bootStartedMs?: number,
|
||||
* signalState?: Map<number, { signal: string, atMs: number }>,
|
||||
* shellJobs?: Array<{ id?: number, done?: boolean, pgid?: number, sid?: number, label?: string }>,
|
||||
* ipcStats?: { processGroups?: Record<string, unknown> } | null
|
||||
* shellJobs?: Array<{ id?: number, done?: boolean, stopped?: boolean, pgid?: number, sid?: number, label?: string }>,
|
||||
* ipcStats?: { processGroups?: Record<string, unknown> } | null,
|
||||
* logicalFdRows?: Array<{ fd: number, target: string }>
|
||||
* }} opts
|
||||
*/
|
||||
export function bareOsProcessTableSnapshot(opts = {}) {
|
||||
@@ -16,6 +17,11 @@ export function bareOsProcessTableSnapshot(opts = {}) {
|
||||
const boot = typeof opts.bootStartedMs === 'number' ? opts.bootStartedMs : 0
|
||||
const now = Date.now()
|
||||
const sigState = opts.signalState instanceof Map ? opts.signalState : new Map()
|
||||
const logicalRows = Array.isArray(opts.logicalFdRows) ? opts.logicalFdRows : []
|
||||
const virtualSignalDeliveries = []
|
||||
for (const [pid, v] of sigState.entries()) {
|
||||
virtualSignalDeliveries.push({ pid, signal: v.signal, atMs: v.atMs })
|
||||
}
|
||||
const mk = (pid, ppid, name, startedAtMs) => {
|
||||
const sig = sigState.get(pid)
|
||||
return {
|
||||
@@ -41,10 +47,11 @@ export function bareOsProcessTableSnapshot(opts = {}) {
|
||||
pgid,
|
||||
sid: session,
|
||||
name: 'bare-os-shell-job',
|
||||
state: 'running',
|
||||
state: j.stopped ? 'stopped' : 'running',
|
||||
startedAtMs: now,
|
||||
jobId: j.id,
|
||||
label: typeof j.label === 'string' ? j.label.slice(0, 256) : undefined
|
||||
label: typeof j.label === 'string' ? j.label.slice(0, 256) : undefined,
|
||||
stopped: !!j.stopped
|
||||
}
|
||||
})
|
||||
const zombieJobs = jobs.filter((j) => j && j.done === true && typeof j.id === 'number')
|
||||
@@ -67,10 +74,26 @@ export function bareOsProcessTableSnapshot(opts = {}) {
|
||||
fds: []
|
||||
}
|
||||
})
|
||||
const stdioTable = [
|
||||
{ fd: 0, kind: 'stdio', target: '/dev/stdin' },
|
||||
{ fd: 1, kind: 'stdio', target: '/dev/stdout' },
|
||||
{ fd: 2, kind: 'stdio', target: '/dev/stderr' }
|
||||
]
|
||||
const extraFdTable = logicalRows.map((r) => ({
|
||||
fd: r.fd | 0,
|
||||
kind: 'logical',
|
||||
target: String(r.target || '').slice(0, 1024)
|
||||
}))
|
||||
return {
|
||||
schema: 2,
|
||||
schemaVersion: 2,
|
||||
schema: 3,
|
||||
schemaVersion: 3,
|
||||
note: 'Synthetic rows; Bare OS guests do not expose host OS processes.',
|
||||
signalModel: {
|
||||
schema: 1,
|
||||
note: 'Virtual deliveries via ctx.bareOsSendSignal (not full sigaction/sigprocmask).',
|
||||
sigpendingAnalog: virtualSignalDeliveries,
|
||||
sigprocmaskAnalog: []
|
||||
},
|
||||
session: {
|
||||
sessionId: sid || undefined,
|
||||
controllingTty: undefined,
|
||||
@@ -97,12 +120,13 @@ export function bareOsProcessTableSnapshot(opts = {}) {
|
||||
},
|
||||
cwd: '/',
|
||||
fdSummary: {
|
||||
nextFd: 3,
|
||||
nextFd: 3 + extraFdTable.length,
|
||||
reservedStdio: [0, 1, 2],
|
||||
note: 'Additional FDs may appear when pseudo-files or IPC channels are opened.'
|
||||
},
|
||||
jobStats: {
|
||||
running: jobProcs.length,
|
||||
running: jobProcs.filter((j) => !j.stopped).length,
|
||||
stopped: jobProcs.filter((j) => j.stopped).length,
|
||||
zombie: zombieJobs.length
|
||||
},
|
||||
processes: [
|
||||
@@ -114,12 +138,14 @@ export function bareOsProcessTableSnapshot(opts = {}) {
|
||||
sid: 1,
|
||||
pgid: 3,
|
||||
cwd: '/',
|
||||
fds: [0, 1, 2]
|
||||
fds: [0, 1, 2],
|
||||
fdTable: [...stdioTable, ...extraFdTable]
|
||||
},
|
||||
...jobProcs.map((p) => ({
|
||||
...p,
|
||||
cwd: typeof p.cwd === 'string' ? p.cwd : '/',
|
||||
fds: Array.isArray(p.fds) ? p.fds : [0, 1, 2]
|
||||
fds: Array.isArray(p.fds) ? p.fds : [0, 1, 2],
|
||||
fdTable: [...stdioTable]
|
||||
})),
|
||||
...zombieProcs
|
||||
],
|
||||
|
||||
@@ -357,7 +357,7 @@ export function buildBareOsRuntimeCaps(shellEnv, extra = {}) {
|
||||
vfsWatchPseudoMetrics: vfsWatchPseudoOn,
|
||||
envDashSAndEnvFile: envDashSOn,
|
||||
shellParamExpansionV2: shellParamV2On,
|
||||
procCgroupsTcpStubs: true,
|
||||
procLinuxCompatCgroupsNet: true,
|
||||
procKernelExtRegistry: true,
|
||||
initdIdleStop: true,
|
||||
initdUnitsDFragments: true,
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Best-effort Hyperdrive → statvfs-like counters for `/proc/bare_os_resources` and `df`.
|
||||
* Hyperdrive versions differ; probes are defensive.
|
||||
*/
|
||||
import b4a from 'b4a'
|
||||
|
||||
/**
|
||||
* @param {unknown} drive
|
||||
* @returns {{ f_bsize: number, f_frsize: number, f_blocks: number, f_bfree: number, f_bavail: number, f_files: number | null, f_ffree: number | null, f_namemax: number, fsidPrefixHex?: string } | null}
|
||||
*/
|
||||
export function bareOsStatvfsFromHyperdrive(drive) {
|
||||
if (!drive || typeof drive !== 'object') return null
|
||||
const bsize = 4096
|
||||
/** @type {number} */
|
||||
let usedBytes = 0
|
||||
try {
|
||||
const c = /** @type {{ byteLength?: number, tree?: { byteLength?: number, length?: number } }} */ (
|
||||
drive
|
||||
).core
|
||||
if (c && typeof c.byteLength === 'number') usedBytes = c.byteLength
|
||||
else if (c && c.tree && typeof c.tree.byteLength === 'number')
|
||||
usedBytes = c.tree.byteLength
|
||||
else if (c && c.tree && typeof c.tree.length === 'number')
|
||||
usedBytes = Math.max(usedBytes, (c.tree.length | 0) * 256)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
if (!Number.isFinite(usedBytes) || usedBytes < 0) return null
|
||||
const usedBlocks = Math.max(1, Math.ceil(usedBytes / bsize))
|
||||
const headroom = Math.max(4096, usedBlocks)
|
||||
const blocks = usedBlocks + headroom
|
||||
const bfree = Math.max(0, blocks - usedBlocks)
|
||||
let fsidPrefixHex
|
||||
try {
|
||||
const k = /** @type {{ key?: Uint8Array }} */ (drive).key
|
||||
if (k && k.byteLength) fsidPrefixHex = b4a.toString(k, 'hex').slice(0, 16)
|
||||
} catch {
|
||||
/* optional */
|
||||
}
|
||||
return {
|
||||
f_bsize: bsize,
|
||||
f_frsize: bsize,
|
||||
f_blocks: blocks,
|
||||
f_bfree: bfree,
|
||||
f_bavail: bfree,
|
||||
f_files: null,
|
||||
f_ffree: null,
|
||||
f_namemax: 255,
|
||||
fsidPrefixHex
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
/** @typedef {'fs' | 'proc' | 'ipc' | 'signal' | 'vfs_meta'} BareOsSyscallCategory */
|
||||
|
||||
/**
|
||||
* Rich syscall table for `/proc/bare_os/syscalls.json` (schema v3+).
|
||||
* Rich syscall table for `/proc/bare_os/syscalls.json` (schema v3+; v4 adds fd/signal models in index.js).
|
||||
* @type {ReadonlyArray<{ name: string, category: BareOsSyscallCategory, stability: BareOsSyscallStability }>}
|
||||
*/
|
||||
export const BARE_OS_SYSCALL_OPS_DETAIL = Object.freeze([
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Optional ACL enforcement using `PATH.bare_acl` sidecars (same layout as setfacl/getfacl).
|
||||
*/
|
||||
import b4a from 'b4a'
|
||||
|
||||
/**
|
||||
* @param {Record<string, string>} env
|
||||
* @param {import('hyperdrive').default} drive
|
||||
* @param {string} drivePath absolute path on the Hyperdrive (no leading slash inconsistency — callers pass the same `path` as `drive.get`)
|
||||
* @param {'read' | 'write'} op
|
||||
*/
|
||||
export async function bareOsVfsAclDeniesDriveOp(env, drive, drivePath, op) {
|
||||
const on =
|
||||
env.BARE_OS_VFS_ENFORCE_ACL === '1' ||
|
||||
env.BARE_OS_VFS_ENFORCE_ACL === 'true'
|
||||
if (!on || !drive || typeof drive.get !== 'function') return false
|
||||
const p = String(drivePath || '').replace(/\/+$/, '') || '/'
|
||||
const sidePath = p + '.bare_acl'
|
||||
let raw
|
||||
try {
|
||||
raw = await drive.get(sidePath, { follow: false })
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
if (!raw || !raw.byteLength) return false
|
||||
const text = b4a.toString(raw)
|
||||
const uid = String(env.UID || '')
|
||||
const re = new RegExp(
|
||||
'^user:' + uid.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ':([rwx-]{3})',
|
||||
'm'
|
||||
)
|
||||
const m = text.match(re)
|
||||
if (!m) return false
|
||||
const perm = m[1]
|
||||
if (op === 'read' && !perm.includes('r')) return true
|
||||
if (op === 'write' && !perm.includes('w')) return true
|
||||
return false
|
||||
}
|
||||
@@ -408,3 +408,31 @@ export async function saveVaultToDrive(ctx) {
|
||||
secureZero(vaultKey)
|
||||
ctx.console.log(`Vault saved (${Object.keys(indexFiles).length} files)`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a non-secret rotation / handoff checkpoint to the personal drive (plaintext NDJSON audit).
|
||||
* Signing keys stay in the vault; this records operator metadata only.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {Record<string, unknown>} row
|
||||
*/
|
||||
export async function bareOsAppendVaultRotationCheckpoint(ctx, row) {
|
||||
const drive = ctx.personalDrive
|
||||
if (!drive || typeof drive.put !== 'function') {
|
||||
throw new Error('bareOsAppendVaultRotationCheckpoint: personal drive unavailable')
|
||||
}
|
||||
const line =
|
||||
JSON.stringify({
|
||||
schema: 1,
|
||||
ts: Date.now(),
|
||||
...row
|
||||
}) + '\n'
|
||||
const path = '/.bare/vault-rotation-audit.ndjson'
|
||||
let prev = ''
|
||||
try {
|
||||
const b = await drive.get(path, { follow: false })
|
||||
if (b) prev = b4a.toString(b)
|
||||
} catch {
|
||||
/* new */
|
||||
}
|
||||
await drive.put(path, b4a.from(prev + line))
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ const SHELL_BUILTINS = new Set([
|
||||
'jobs',
|
||||
'fg',
|
||||
'bg',
|
||||
'wait'
|
||||
'wait',
|
||||
'suspend-job',
|
||||
'trap'
|
||||
])
|
||||
|
||||
function isShellBuiltin(cmd) {
|
||||
@@ -1492,7 +1494,9 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
origLog.call(ctx.console, '')
|
||||
} else {
|
||||
for (const j of list) {
|
||||
const st = j.done ? 'Done' : 'Running'
|
||||
let st = 'Running'
|
||||
if (j.done) st = 'Done'
|
||||
else if (j.stopped) st = 'Stopped'
|
||||
const pg =
|
||||
typeof j.pgid === 'number' && typeof j.sid === 'number'
|
||||
? ` sid=${j.sid} pgid=${j.pgid}`
|
||||
@@ -1519,6 +1523,7 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
origErr.call(ctx.console, 'fg: no such job')
|
||||
ctx.exitCode = 1
|
||||
} else {
|
||||
if (j.stopped) j.stopped = false
|
||||
try {
|
||||
await j.promise
|
||||
} catch {
|
||||
@@ -1527,11 +1532,82 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
ctx.exitCode = 0
|
||||
}
|
||||
} else if (name === 'bg') {
|
||||
origErr.call(
|
||||
ctx.console,
|
||||
'bg: job resume is not supported (no stopped jobs)'
|
||||
)
|
||||
const list = ctx.shellBackgroundJobs?.list || []
|
||||
const stopped = list.filter((j) => j && !j.done && j.stopped)
|
||||
if (!stopped.length) {
|
||||
origErr.call(ctx.console, 'bg: no stopped jobs')
|
||||
ctx.exitCode = 1
|
||||
} else {
|
||||
let targets = stopped
|
||||
const arg = argv[1]
|
||||
if (arg) {
|
||||
const raw = arg.startsWith('%') ? arg.slice(1) : arg
|
||||
const jid = Number.parseInt(raw, 10)
|
||||
if (Number.isFinite(jid)) {
|
||||
targets = stopped.filter((j) => j.id === jid)
|
||||
}
|
||||
}
|
||||
if (!targets.length) {
|
||||
origErr.call(ctx.console, 'bg: no stopped jobs')
|
||||
ctx.exitCode = 1
|
||||
} else {
|
||||
for (const j of targets) j.stopped = false
|
||||
ctx.exitCode = 0
|
||||
}
|
||||
}
|
||||
} else if (name === 'suspend-job') {
|
||||
const list = ctx.shellBackgroundJobs?.list || []
|
||||
let candidates = list.filter((j) => j && !j.done && !j.stopped)
|
||||
const arg = argv[1]
|
||||
if (arg) {
|
||||
const raw = arg.startsWith('%') ? arg.slice(1) : arg
|
||||
const jid = Number.parseInt(raw, 10)
|
||||
if (Number.isFinite(jid)) {
|
||||
candidates = list.filter((j) => j && !j.done && j.id === jid)
|
||||
}
|
||||
}
|
||||
const j = candidates.length ? candidates[candidates.length - 1] : null
|
||||
if (!j) {
|
||||
origErr.call(ctx.console, 'suspend-job: no such job')
|
||||
ctx.exitCode = 1
|
||||
} else {
|
||||
j.stopped = true
|
||||
ctx.exitCode = 0
|
||||
}
|
||||
} else if (name === 'trap') {
|
||||
if (argv[1] === '-l' || argv[1] === '--list') {
|
||||
ctx.console.log('HUP INT KILL TERM PIPE CHLD USR1 USR2 EXIT')
|
||||
} else if (argv[1] === '-p') {
|
||||
const h =
|
||||
ctx.shellTrapHandlers && typeof ctx.shellTrapHandlers === 'object'
|
||||
? ctx.shellTrapHandlers
|
||||
: {}
|
||||
for (const k of Object.keys(h)) {
|
||||
ctx.console.log(
|
||||
`trap -- '${String(
|
||||
/** @type {Record<string, string>} */ (h)[k]
|
||||
).replace(/'/g, `'\\''`)}' ${k}`
|
||||
)
|
||||
}
|
||||
} else if (argv.length < 3) {
|
||||
origErr.call(ctx.console, 'trap: usage: trap COMMAND SIGNAL')
|
||||
ctx.exitCode = 1
|
||||
} else {
|
||||
if (!ctx.shellTrapHandlers || typeof ctx.shellTrapHandlers !== 'object')
|
||||
ctx.shellTrapHandlers = Object.create(null)
|
||||
const cmd = argv[1]
|
||||
const sig = String(argv[2] || '')
|
||||
.replace(/^SIG/i, '')
|
||||
.toUpperCase()
|
||||
if (cmd === '-' || cmd === '') {
|
||||
delete /** @type {Record<string, string>} */ (ctx.shellTrapHandlers)[
|
||||
sig
|
||||
]
|
||||
} else {
|
||||
/** @type {Record<string, string>} */ (ctx.shellTrapHandlers)[sig] =
|
||||
cmd
|
||||
}
|
||||
}
|
||||
} else if (name === 'wait') {
|
||||
const list = ctx.shellBackgroundJobs?.list || []
|
||||
const arg = argv[1]
|
||||
@@ -1737,8 +1813,8 @@ function scheduleBackgroundShell(ctx, toks) {
|
||||
syncBareOsExitStatusEnv(childCtx)
|
||||
return 'ok'
|
||||
})()
|
||||
/** @type {{ id: number, label: string, promise: Promise<string>, done: boolean, pgid: number, sid: number }} */
|
||||
const entry = { id, label, promise, done: false, pgid, sid }
|
||||
/** @type {{ id: number, label: string, promise: Promise<string>, done: boolean, stopped: boolean, pgid: number, sid: number }} */
|
||||
const entry = { id, label, promise, done: false, stopped: false, pgid, sid }
|
||||
ctx.shellBackgroundJobs.list.push(entry)
|
||||
promise.finally(() => {
|
||||
entry.done = true
|
||||
|
||||
@@ -339,9 +339,11 @@ export function isVirtualMountPoint(abs) {
|
||||
abs === '/' ||
|
||||
abs === '/home' ||
|
||||
abs === '/mnt' ||
|
||||
abs === '/mirror' ||
|
||||
abs === '/var' ||
|
||||
abs === '/home/' ||
|
||||
abs === '/mnt/' ||
|
||||
abs === '/mirror/' ||
|
||||
abs === '/var/' ||
|
||||
n === '/proc' ||
|
||||
n === '/proc/self' ||
|
||||
|
||||
@@ -3,6 +3,7 @@ import b4a from 'b4a'
|
||||
import { raceWithAbortAndTimeout } from './bare-os-abort.js'
|
||||
import { bareOsIpcLogicalToActualFifoName } from './bare-os-ipc-namespace.js'
|
||||
import { listBareInitdJournalUnits } from './bare-initd-journal.js'
|
||||
import { bareOsVfsAclDeniesDriveOp } from './bare-os-vfs-acl-enforce.js'
|
||||
import {
|
||||
extractBareOs,
|
||||
identityNames,
|
||||
@@ -385,7 +386,10 @@ export const BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE = Object.free
|
||||
* sysClassNetLoText?: () => string,
|
||||
* hostProcStatsRef?: { stats?: unknown } | null,
|
||||
* ipcFifoLogicalToActual?: (logicalName: string) => string,
|
||||
* getProcSelfExtraFds?: () => { fdNum: string, target: string }[]
|
||||
* getProcSelfExtraFds?: () => { fdNum: string, target: string }[],
|
||||
* getProcSyntheticLinuxCompat?: () => { sessionId: string, swarmPeerCount: number, peerIds: string[] } | null | undefined,
|
||||
* getAuxiliaryMountLines?: () => (string | null | undefined)[],
|
||||
* getAuxiliaryDrives?: () => unknown[] | null | undefined
|
||||
* }} [vfsOptions]
|
||||
*/
|
||||
export function createVfs(
|
||||
@@ -640,6 +644,18 @@ export function createVfs(
|
||||
typeof vfsOptions.getVirtualReaders === 'function'
|
||||
? vfsOptions.getVirtualReaders
|
||||
: null
|
||||
const getProcSyntheticLinuxCompat =
|
||||
typeof vfsOptions.getProcSyntheticLinuxCompat === 'function'
|
||||
? vfsOptions.getProcSyntheticLinuxCompat
|
||||
: null
|
||||
const getAuxiliaryMountLines =
|
||||
typeof vfsOptions.getAuxiliaryMountLines === 'function'
|
||||
? vfsOptions.getAuxiliaryMountLines
|
||||
: null
|
||||
const getAuxiliaryDrives =
|
||||
typeof vfsOptions.getAuxiliaryDrives === 'function'
|
||||
? vfsOptions.getAuxiliaryDrives
|
||||
: null
|
||||
const unionReadPrefixes = Array.isArray(vfsOptions.unionReadPrefixes)
|
||||
? vfsOptions.unionReadPrefixes.filter(
|
||||
(s) => typeof s === 'string' && s.startsWith('/')
|
||||
@@ -687,9 +703,42 @@ export function createVfs(
|
||||
|
||||
const binCacheEnabled =
|
||||
env.BARE_OS_VFS_BIN_CACHE === '1' || env.BARE_OS_VFS_BIN_CACHE === 'true'
|
||||
/** @type {Map<string, Uint8Array>} */
|
||||
const binReadCache = binCacheEnabled ? new Map() : null
|
||||
const binCacheBlake2b =
|
||||
binCacheEnabled &&
|
||||
(env.BARE_OS_VFS_BIN_CACHE_BLAKE2B === '1' ||
|
||||
env.BARE_OS_VFS_BIN_CACHE_BLAKE2B === 'true')
|
||||
/** @type {Map<string, Uint8Array> | null} */
|
||||
const binReadCache = binCacheEnabled && !binCacheBlake2b ? new Map() : null
|
||||
/** @type {Map<string, Uint8Array> | null} digest hex → bytes */
|
||||
const binDigestCache = binCacheBlake2b ? new Map() : null
|
||||
/** @type {Map<string, string> | null} logical path → digest */
|
||||
const binPathToBlakeDigest = binCacheBlake2b ? new Map() : null
|
||||
/** @type {Map<string, number> | null} digest refcount */
|
||||
const binDigestRefcount = binCacheBlake2b ? new Map() : null
|
||||
/** @type {string[] | null} */
|
||||
const binBlake2bLruPaths = binCacheBlake2b ? [] : null
|
||||
const BIN_READ_CACHE_MAX = 64
|
||||
|
||||
function touchBinBlake2bLru(p) {
|
||||
if (!binBlake2bLruPaths || !binPathToBlakeDigest) return
|
||||
const i = binBlake2bLruPaths.indexOf(p)
|
||||
if (i >= 0) binBlake2bLruPaths.splice(i, 1)
|
||||
binBlake2bLruPaths.push(p)
|
||||
while (binBlake2bLruPaths.length > BIN_READ_CACHE_MAX) {
|
||||
const victim = binBlake2bLruPaths.shift()
|
||||
if (!victim) continue
|
||||
const hex = binPathToBlakeDigest.get(victim)
|
||||
if (!hex) continue
|
||||
binPathToBlakeDigest.delete(victim)
|
||||
const n = (binDigestRefcount.get(hex) || 1) - 1
|
||||
if (n <= 0) {
|
||||
binDigestRefcount.delete(hex)
|
||||
binDigestCache.delete(hex)
|
||||
} else {
|
||||
binDigestRefcount.set(hex, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
const sysClassNetLoText =
|
||||
typeof vfsOptions.sysClassNetLoText === 'function'
|
||||
? vfsOptions.sysClassNetLoText
|
||||
@@ -921,16 +970,114 @@ export function createVfs(
|
||||
return '/bin/sh (bare-os pseudo inode; no backing host file)\n'
|
||||
}
|
||||
|
||||
function pseudoSelfCgroupsText() {
|
||||
return '0::/bare-os.scope\n'
|
||||
function bareOsSanitizeCgroupSegment(s) {
|
||||
return String(s || 'unknown')
|
||||
.replace(/[^a-zA-Z0-9._-]/g, '_')
|
||||
.slice(0, 128)
|
||||
}
|
||||
|
||||
/** @returns {{ sessionId: string, swarmPeerCount: number, peerIds: string[] }} */
|
||||
function readProcSyntheticLinuxCompat() {
|
||||
let sessionId = String(env.BARE_OS_SESSION_ID || env.BARE_OS_TRACE_ID || '')
|
||||
.trim()
|
||||
let swarmPeerCount = 0
|
||||
let peerIds = []
|
||||
try {
|
||||
const h = getProcSyntheticLinuxCompat ? getProcSyntheticLinuxCompat() : null
|
||||
if (h && typeof h === 'object') {
|
||||
if (h.sessionId != null && String(h.sessionId).trim())
|
||||
sessionId = String(h.sessionId).trim()
|
||||
const n = Number(h.swarmPeerCount)
|
||||
if (Number.isFinite(n) && n >= 0) swarmPeerCount = Math.min(4096, n | 0)
|
||||
if (Array.isArray(h.peerIds))
|
||||
peerIds = h.peerIds.map((x) => String(x || '')).filter(Boolean)
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
if (!sessionId) sessionId = 'session'
|
||||
return { sessionId, swarmPeerCount, peerIds }
|
||||
}
|
||||
|
||||
/**
|
||||
* Linux cgroup v2 single-column lines, scoped to the guest session (not host cgroups).
|
||||
*/
|
||||
function pseudoSelfCgroupsText() {
|
||||
const { sessionId } = readProcSyntheticLinuxCompat()
|
||||
const sid = bareOsSanitizeCgroupSegment(sessionId)
|
||||
return [
|
||||
'# bare_os synthetic cgroup v2 view (guest session + swarm scope; not the host cgroup hierarchy)',
|
||||
'0::/bare-os.scope',
|
||||
`0::/bare-os.session/${sid}/init`,
|
||||
`0::/bare-os.session/${sid}/swarm`,
|
||||
''
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
/** IPv4:port as in /proc/net/tcp (little-endian quad hex + port hex). */
|
||||
function bareOsProcNetIpv4PortHex(ip, port) {
|
||||
const parts = String(ip || '0.0.0.0').split('.')
|
||||
const a = Number(parts[0]) || 0
|
||||
const b = Number(parts[1]) || 0
|
||||
const c = Number(parts[2]) || 0
|
||||
const d = Number(parts[3]) || 0
|
||||
const addr = (a | (b << 8) | (c << 16) | (d << 24)) >>> 0
|
||||
const p = port & 0xffff
|
||||
return (
|
||||
addr.toString(16).padStart(8, '0') +
|
||||
':' +
|
||||
p.toString(16).padStart(4, '0')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Hyperswarm / replication streams as Linux-shaped /proc/net/tcp rows (inode encodes slot).
|
||||
*/
|
||||
function pseudoNetTcpText() {
|
||||
return 'sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n'
|
||||
const { swarmPeerCount, peerIds } = readProcSyntheticLinuxCompat()
|
||||
const nPeers = Math.max(swarmPeerCount, peerIds.length)
|
||||
const lines = [
|
||||
' sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode',
|
||||
'# bare_os: logical swarm/replication endpoints (not host TCP); st 0A=LISTEN 01=ESTABLISHED'
|
||||
]
|
||||
lines.push(
|
||||
` 0: ${bareOsProcNetIpv4PortHex('127.0.0.1', 57800)} 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 800000`
|
||||
)
|
||||
let inode = 800001
|
||||
for (let i = 0; i < nPeers; i++) {
|
||||
const id = peerIds[i] || '0'.repeat(64)
|
||||
const h = id.slice(0, 8) || '00000000'
|
||||
const v = Number.parseInt(h, 16) || 0
|
||||
const o1 = v & 255
|
||||
const o2 = (v >>> 8) & 255
|
||||
const o3 = (v >>> 16) & 255
|
||||
const o4 = (v >>> 24) & 255
|
||||
const remIp = `${o1}.${o2}.${o3}.${o4}`
|
||||
lines.push(
|
||||
` ${i + 1}: ${bareOsProcNetIpv4PortHex('127.0.0.1', 58000 + i)} ${bareOsProcNetIpv4PortHex(remIp, 57900 + i)} 01 00000000:00000000 00:00000000 00000000 0 0 ${inode}`
|
||||
)
|
||||
inode++
|
||||
}
|
||||
lines.push('')
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
function pseudoNetUdpText() {
|
||||
return 'sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref\n'
|
||||
const { swarmPeerCount } = readProcSyntheticLinuxCompat()
|
||||
const lines = [
|
||||
' sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref',
|
||||
'# bare_os: logical UDP-shaped discovery/datagram hints (not host UDP)'
|
||||
]
|
||||
lines.push(
|
||||
` 0: ${bareOsProcNetIpv4PortHex('0.0.0.0', 49721)} 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 810000 2`
|
||||
)
|
||||
if (swarmPeerCount > 0) {
|
||||
lines.push(
|
||||
` 1: ${bareOsProcNetIpv4PortHex('127.0.0.1', 49722)} 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 810001 2`
|
||||
)
|
||||
}
|
||||
lines.push('')
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1099,7 +1246,7 @@ export function createVfs(
|
||||
if (f === 'bare_os_syscalls') {
|
||||
const t = procBareOsSyscallsText
|
||||
? procBareOsSyscallsText()
|
||||
: '{"schemaVersion":3,"ops":[],"errnoHints":{}}\n'
|
||||
: '{"schemaVersion":4,"ops":[],"errnoHints":{},"fdModel":{"schema":1},"signalModel":{"schema":1,"names":[]}}\n'
|
||||
return utf8Encode(t)
|
||||
}
|
||||
if (f === 'bare_os_metrics_prom') {
|
||||
@@ -2939,9 +3086,56 @@ export function createVfs(
|
||||
const rw = ent.writable ? 'rw' : 'ro'
|
||||
lines.push(`bare-os-${label} /mnt/${label} hyperdrive ${rw} 0 0`)
|
||||
}
|
||||
try {
|
||||
const extra = getAuxiliaryMountLines ? getAuxiliaryMountLines() : []
|
||||
if (Array.isArray(extra)) {
|
||||
for (const row of extra) {
|
||||
if (typeof row === 'string' && row.trim()) lines.push(row.trim())
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return lines.join('\n') + '\n'
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional read-only auxiliary Hyperdrives under `/mirror/aux0`, `/mirror/aux1`, …
|
||||
* @returns {null | Record<string, unknown>}
|
||||
*/
|
||||
function routeMirror(absPath) {
|
||||
const aux = getAuxiliaryDrives ? getAuxiliaryDrives() : null
|
||||
if (!Array.isArray(aux) || aux.length === 0) return null
|
||||
if (absPath === '/mirror' || absPath === '/mirror/') {
|
||||
return { virtualMirrorRoot: true }
|
||||
}
|
||||
if (!absPath.startsWith('/mirror/')) return null
|
||||
const rest = absPath.slice('/mirror/'.length)
|
||||
const slash = rest.indexOf('/')
|
||||
const seg = slash === -1 ? rest : rest.slice(0, slash)
|
||||
const tail = slash === -1 ? '' : rest.slice(slash + 1)
|
||||
if (!seg) return { virtualMirrorRoot: true }
|
||||
const m = /^aux(\d+)$/.exec(seg)
|
||||
if (!m) {
|
||||
return { drive: systemDrive, path: absPath }
|
||||
}
|
||||
const idx = Number(m[1])
|
||||
const drive = /** @type {unknown} */ (aux[idx])
|
||||
if (
|
||||
!drive ||
|
||||
typeof (/** @type {{ get?: unknown }} */ (drive).get) !== 'function'
|
||||
) {
|
||||
return { drive: systemDrive, path: absPath }
|
||||
}
|
||||
const sub = tail ? '/' + tail.replace(/^\/+/, '') : '/'
|
||||
const p = unixPathResolve('/', sub)
|
||||
return {
|
||||
drive: /** @type {import('hyperdrive').default} */ (drive),
|
||||
path: p,
|
||||
mntReadOnly: true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {null | Record<string, unknown>}
|
||||
*/
|
||||
@@ -2970,6 +3164,8 @@ export function createVfs(
|
||||
* Virtual /home lists only the active session dir; /home/<active>/… is the personal drive.
|
||||
*/
|
||||
function route(absPath) {
|
||||
const mirR = routeMirror(absPath)
|
||||
if (mirR) return mirR
|
||||
const mntR = routeMnt(absPath)
|
||||
if (mntR) return mntR
|
||||
|
||||
@@ -3099,6 +3295,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -3171,6 +3368,9 @@ export function createVfs(
|
||||
}
|
||||
|
||||
async function lstatFromAbs(abs) {
|
||||
if (abs === '/mirror' || abs === '/mirror/') {
|
||||
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
||||
}
|
||||
if (abs === '/mnt' || abs === '/mnt/') {
|
||||
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
||||
}
|
||||
@@ -3182,7 +3382,7 @@ export function createVfs(
|
||||
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
||||
}
|
||||
const r = route(abs)
|
||||
if (r.virtualMntRoot) {
|
||||
if (r.virtualMntRoot || r.virtualMirrorRoot) {
|
||||
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
||||
}
|
||||
if (r.virtualVarRoot) {
|
||||
@@ -3278,6 +3478,8 @@ export function createVfs(
|
||||
if (
|
||||
abs === '/mnt' ||
|
||||
abs === '/mnt/' ||
|
||||
abs === '/mirror' ||
|
||||
abs === '/mirror/' ||
|
||||
abs === '/home' ||
|
||||
abs === '/' ||
|
||||
normVar === '/var' ||
|
||||
@@ -3290,6 +3492,7 @@ export function createVfs(
|
||||
const r0 = route(abs)
|
||||
if (
|
||||
r0.virtualMntRoot ||
|
||||
r0.virtualMirrorRoot ||
|
||||
r0.virtualVarRoot ||
|
||||
r0.virtualPseudo ||
|
||||
r0.virtualSnapshotRoot ||
|
||||
@@ -3310,6 +3513,7 @@ export function createVfs(
|
||||
cur === '/' ||
|
||||
cur === '/home' ||
|
||||
cur === '/mnt' ||
|
||||
cur === '/mirror' ||
|
||||
curNorm === '/var' ||
|
||||
curNorm === '/var/log' ||
|
||||
curNorm === '/tmp'
|
||||
@@ -3317,7 +3521,12 @@ export function createVfs(
|
||||
return cur
|
||||
}
|
||||
const r = route(cur)
|
||||
if (r.virtualMntRoot || r.virtualVarRoot || r.virtualPseudo) {
|
||||
if (
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
return cur
|
||||
}
|
||||
const { drive, path: p } = r
|
||||
@@ -3861,6 +4070,12 @@ export function createVfs(
|
||||
}
|
||||
}
|
||||
const r = route(abs)
|
||||
if (r.virtualMirrorRoot) {
|
||||
const aux = getAuxiliaryDrives ? getAuxiliaryDrives() : []
|
||||
return Array.isArray(aux)
|
||||
? aux.map((_, i) => 'aux' + i).sort()
|
||||
: []
|
||||
}
|
||||
if (r.virtualMntRoot) {
|
||||
return [...getMntMap().keys()].sort()
|
||||
}
|
||||
@@ -3879,6 +4094,10 @@ export function createVfs(
|
||||
if (abs === '/' && !names.includes('mnt')) {
|
||||
names.push('mnt')
|
||||
}
|
||||
if (abs === '/' && !names.includes('mirror')) {
|
||||
const aux = getAuxiliaryDrives ? getAuxiliaryDrives() : []
|
||||
if (Array.isArray(aux) && aux.length) names.push('mirror')
|
||||
}
|
||||
if (abs === '/' && !names.includes('var')) {
|
||||
names.push('var')
|
||||
}
|
||||
@@ -3920,6 +4139,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -3957,6 +4177,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -4020,6 +4241,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -4039,6 +4261,9 @@ export function createVfs(
|
||||
if (isHyperdriveRootPath(p)) {
|
||||
throw new Error('Cannot write directory: ' + abs)
|
||||
}
|
||||
if (await bareOsVfsAclDeniesDriveOp(env, drive, p, 'write')) {
|
||||
throw new Error('EACCES: ACL enforces deny write: ' + abs)
|
||||
}
|
||||
const existing = await entryOn(drive, p, { follow: false })
|
||||
const hadBlob = !!existing?.value?.blob
|
||||
if (hadBlob) await assertTraverseTo(abs, 'write')
|
||||
@@ -4137,12 +4362,22 @@ export function createVfs(
|
||||
}
|
||||
return null
|
||||
}
|
||||
if (r.virtualHomeDir || r.virtualMntRoot || r.virtualVarRoot)
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot
|
||||
)
|
||||
return null
|
||||
await assertTraverseTo(abs, 'read')
|
||||
const absFollowed = await resolveSymlinksOnLogicalAbs(abs)
|
||||
const r2 = route(absFollowed)
|
||||
if (r2.virtualHomeDir || r2.virtualMntRoot || r2.virtualVarRoot)
|
||||
if (
|
||||
r2.virtualHomeDir ||
|
||||
r2.virtualMntRoot ||
|
||||
r2.virtualMirrorRoot ||
|
||||
r2.virtualVarRoot
|
||||
)
|
||||
return null
|
||||
if (r2.virtualPseudo) {
|
||||
await assertTraverseTo(absFollowed, 'read')
|
||||
@@ -4208,6 +4443,13 @@ export function createVfs(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (binDigestCache && drive === systemDrive && absFollowed.startsWith('/bin/')) {
|
||||
const dh = binPathToBlakeDigest.get(absFollowed)
|
||||
if (dh) {
|
||||
const hit = binDigestCache.get(dh)
|
||||
if (hit) return new Uint8Array(hit)
|
||||
}
|
||||
}
|
||||
if (
|
||||
binReadCache &&
|
||||
drive === systemDrive &&
|
||||
@@ -4216,19 +4458,58 @@ export function createVfs(
|
||||
const hit = binReadCache.get(absFollowed)
|
||||
if (hit) return new Uint8Array(hit)
|
||||
}
|
||||
if (await bareOsVfsAclDeniesDriveOp(env, drive, p, 'read')) {
|
||||
throw new Error('EACCES: ACL enforces deny read: ' + absFollowed)
|
||||
}
|
||||
const got = await drive.get(p, { follow: false })
|
||||
if (got && drive === systemDrive && absFollowed.startsWith('/bin/')) {
|
||||
if (
|
||||
binReadCache &&
|
||||
drive === systemDrive &&
|
||||
absFollowed.startsWith('/bin/') &&
|
||||
got
|
||||
binDigestCache &&
|
||||
binPathToBlakeDigest &&
|
||||
binDigestRefcount &&
|
||||
binBlake2bLruPaths
|
||||
) {
|
||||
try {
|
||||
const { createHash: ch } = await import('bare-crypto')
|
||||
if (typeof ch !== 'function') throw new Error('no createHash')
|
||||
const u8 = got instanceof Uint8Array ? got : new Uint8Array(got)
|
||||
const h = ch('blake2b')
|
||||
h.update(u8)
|
||||
const dig = String(h.digest('hex'))
|
||||
const oldHex = binPathToBlakeDigest.get(absFollowed)
|
||||
if (oldHex === dig) {
|
||||
touchBinBlake2bLru(absFollowed)
|
||||
} else {
|
||||
if (oldHex) {
|
||||
const n0 = (binDigestRefcount.get(oldHex) || 1) - 1
|
||||
if (n0 <= 0) {
|
||||
binDigestRefcount.delete(oldHex)
|
||||
binDigestCache.delete(oldHex)
|
||||
} else {
|
||||
binDigestRefcount.set(oldHex, n0)
|
||||
}
|
||||
}
|
||||
binPathToBlakeDigest.set(absFollowed, dig)
|
||||
if (!binDigestCache.has(dig)) {
|
||||
binDigestCache.set(dig, new Uint8Array(u8))
|
||||
}
|
||||
binDigestRefcount.set(
|
||||
dig,
|
||||
(binDigestRefcount.get(dig) || 0) + 1
|
||||
)
|
||||
touchBinBlake2bLru(absFollowed)
|
||||
}
|
||||
} catch {
|
||||
/* ignore blake2b cache failures */
|
||||
}
|
||||
} else if (binReadCache) {
|
||||
if (binReadCache.size >= BIN_READ_CACHE_MAX) {
|
||||
const first = binReadCache.keys().next().value
|
||||
binReadCache.delete(first)
|
||||
}
|
||||
binReadCache.set(absFollowed, new Uint8Array(got))
|
||||
}
|
||||
}
|
||||
return got
|
||||
})(),
|
||||
abortOpts,
|
||||
@@ -4281,6 +4562,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -4328,7 +4610,13 @@ export function createVfs(
|
||||
if (r.node === 'enoent') return false
|
||||
return true
|
||||
}
|
||||
if (r.virtualHomeDir || r.virtualMntRoot || r.virtualVarRoot) return true
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot
|
||||
)
|
||||
return true
|
||||
const { drive, path: p } = r
|
||||
if (isHyperdriveRootPath(p)) return true
|
||||
return drive.exists(p)
|
||||
@@ -4360,6 +4648,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -4430,6 +4719,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -4590,6 +4880,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -4637,6 +4928,7 @@ export function createVfs(
|
||||
if (
|
||||
r.virtualHomeDir ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualPseudo
|
||||
) {
|
||||
@@ -4766,6 +5058,7 @@ export function createVfs(
|
||||
r.virtualHomeDir ||
|
||||
r.virtualVarRoot ||
|
||||
r.virtualMntRoot ||
|
||||
r.virtualMirrorRoot ||
|
||||
r.virtualSnapshotRoot ||
|
||||
r.virtualSnapshotSystem
|
||||
) {
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"start": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && bare index.js",
|
||||
"dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && bare index.js",
|
||||
"pear:dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && pear run --dev .",
|
||||
"test": "../../node_modules/.bin/brittle-bare test.identity.js && node --require ./scripts/bare-node-test-shim.cjs ../../node_modules/.bin/brittle-node test.js"
|
||||
"test": "../../node_modules/.bin/brittle-bare test.identity.js && node --require ./scripts/bare-node-test-shim.cjs ../../node_modules/.bin/brittle-node test.js",
|
||||
"test:bare": "../../node_modules/.bin/brittle-bare test.identity.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"autopass": "^3.4.0",
|
||||
|
||||
@@ -793,6 +793,42 @@ test('vfs lstat personal file includes mode uid user mtime', async (t) => {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('vfs syscalls.json uses schema 4 when provider wired', async (t) => {
|
||||
const dir = testCorestoreDir('syscallsproc')
|
||||
const store = new Corestore(dir)
|
||||
const sys = new Hyperdrive(store)
|
||||
const personal = new Hyperdrive(store.namespace('scp'))
|
||||
await sys.ready()
|
||||
await personal.ready()
|
||||
const sample = {
|
||||
schemaVersion: 4,
|
||||
ctxApiVersion: BARE_OS_CTX_API_VERSION,
|
||||
ops: ['readFile'],
|
||||
errnoHints: { ENOENT: 2 },
|
||||
fdModel: { schema: 1, stdio: [0, 1, 2] },
|
||||
signalModel: { schema: 1, names: ['INT'] },
|
||||
atMs: 0
|
||||
}
|
||||
const vfs = createVfs(
|
||||
sys,
|
||||
personal,
|
||||
{ HOME: '/home/g', PWD: '/', PATH: '/bin' },
|
||||
null,
|
||||
{
|
||||
procBareOsSyscallsText() {
|
||||
return `${JSON.stringify(sample)}\n`
|
||||
}
|
||||
}
|
||||
)
|
||||
const buf = await vfs.readFile('/proc/bare_os/syscalls.json')
|
||||
const j = JSON.parse(b4a.toString(buf))
|
||||
t.is(j.schemaVersion, 4)
|
||||
t.ok(j.fdModel && j.fdModel.schema === 1)
|
||||
t.ok(j.signalModel && Array.isArray(j.signalModel.names))
|
||||
await store.close()
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('ls -l long listing uses session user and regular file mode', async (t) => {
|
||||
const lsPath = path.join(__dirname, '../../kernel/bin/ls')
|
||||
const lsSrc = await readFile(lsPath, 'utf8')
|
||||
@@ -5212,6 +5248,8 @@ test('process table snapshot includes processGroups metadata', async (t) => {
|
||||
t.ok(s.processGroups)
|
||||
t.is(s.processGroups.schema, 1)
|
||||
t.ok(String(s.processGroups.killpgAnalog).includes('killpg'))
|
||||
t.is(s.schemaVersion, 3)
|
||||
t.ok(s.signalModel && Array.isArray(s.signalModel.sigpendingAnalog))
|
||||
})
|
||||
|
||||
async function readBuiltBin(name) {
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
"awk [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Pattern-directed scanning and processing. Engine in lib/awk-engine.js; not full POSIX awk.",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "-F sep", "meaning": "[Issue 7 awk] Field separator." },
|
||||
{ "flag": "-v var=value", "meaning": "[Issue 7 awk] Assign variable before script runs." }
|
||||
],
|
||||
"keywords": [
|
||||
"awk",
|
||||
"pattern",
|
||||
|
||||
@@ -6,12 +6,21 @@
|
||||
"cp [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of copy files. Full behavior is defined in packages/bare-os-coreutils/src/cp.js.",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "-R, -r, --recursive", "meaning": "[Issue 7 cp] Recursive directory copy; skips .bareos_empty marker files in tree walks." },
|
||||
{ "flag": "-L, --dereference", "meaning": "[Issue 7 cp] Follow symlinks to copy referent file or directory." },
|
||||
{ "flag": "-P, --no-dereference", "meaning": "[Issue 7 cp] Copy symlink itself (default)." },
|
||||
{ "flag": "-u, --update", "meaning": "[Issue 7 cp] Skip copy when destination mtime >= source mtime." },
|
||||
{ "flag": "-v, --verbose", "meaning": "[Issue 7 cp] Log each copy." },
|
||||
{ "flag": "-p, --preserve", "meaning": "[Issue 7 cp] Preserve timestamps via mtimeMs/ctimeMs on writeFile when supported." },
|
||||
{ "flag": "--preserve=timestamps|time|all", "meaning": "[Issue 7 cp] Subset: timestamps|time|all enables preserveTime only." }
|
||||
],
|
||||
"keywords": [
|
||||
"cp",
|
||||
"bare-os",
|
||||
"coreutils"
|
||||
],
|
||||
"bareOsNotes": "Issue 7 option matrix above is for traceability; behavior is bounded by the Hyperdrive VFS (no hard links, no xattr copy).",
|
||||
"examples": [
|
||||
{
|
||||
"caption": "copy file",
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
"find [PATH...] [EXPRESSION]"
|
||||
],
|
||||
"description": "Walks directories and applies expressions (-name, -type, -print, -maxdepth, logical -and/-or/-not).",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "-name", "meaning": "[Issue 7 find] Glob pattern on basename." },
|
||||
{ "flag": "-type", "meaning": "[Issue 7 find] Filter f, d, or l." },
|
||||
{ "flag": "-maxdepth", "meaning": "[Issue 7 find] Limit walk depth." }
|
||||
],
|
||||
"keywords": [
|
||||
"find",
|
||||
"directory",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"grep [-E|-F] [-i] [-v] [-n] [-c] [-l] [-q] [-s] [-H|-h] [-e pat] ... [-f file] ... [pattern] [file...]"
|
||||
],
|
||||
"description": "Searches input or files for lines matching a pattern. Uses JavaScript RegExp unless -F (fixed string). Not bit-identical to GNU grep.",
|
||||
"bareOsNotes": "POSIX Issue 7 option names are listed below; regex semantics follow JavaScript RegExp unless -F.",
|
||||
"options": [
|
||||
{
|
||||
"flag": "-E",
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
"ln [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of link files. Full behavior is defined in packages/bare-os-coreutils/src/ln.js.",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "-s, --symbolic", "meaning": "[Issue 7 ln] Create symbolic link." },
|
||||
{ "flag": "-f, --force", "meaning": "[Issue 7 ln] Replace existing destination when supported." },
|
||||
{ "flag": "-r, --relative", "meaning": "[Issue 7 ln] Store relative symlink target when requested." }
|
||||
],
|
||||
"keywords": [
|
||||
"ln",
|
||||
"bare-os",
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
"mv [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of move or rename files. Full behavior is defined in packages/bare-os-coreutils/src/mv.js.",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "-L, --dereference", "meaning": "[Issue 7 mv] Follow symlinks when moving file content." },
|
||||
{ "flag": "-P, --no-dereference", "meaning": "[Issue 7 mv] Move symlink node (default for symlinks)." }
|
||||
],
|
||||
"bareOsNotes": "Directories always move recursively (copy+delete); see src/mv.js.",
|
||||
"keywords": [
|
||||
"mv",
|
||||
"bare-os",
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
"sed [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Stream editor with a subset of POSIX sed. Large engine is vendored in lib/sed-engine.js.",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "-n", "meaning": "[Issue 7 sed] Suppress default print when script uses p selectively." },
|
||||
{ "flag": "-e script", "meaning": "[Issue 7 sed] Append edit script." },
|
||||
{ "flag": "-f file", "meaning": "[Issue 7 sed] Read script from file." }
|
||||
],
|
||||
"keywords": [
|
||||
"sed",
|
||||
"stream",
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
"tar [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of tar. Full behavior is defined in packages/bare-os-coreutils/src/tar.js. Extended attributes for unpacked files may be mirrored manually using sibling PATH.bare_xattr.json sidecars (see xattr(1)).",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "-c, -x, -t", "meaning": "[Issue 7 tar] Create, extract, and list modes as implemented in src/tar.js (bounded archive subset)." },
|
||||
{ "flag": "-f", "meaning": "[Issue 7 tar] Archive file path operand." }
|
||||
],
|
||||
"bareOsNotes": "Not full GNU tar; see src/tar.js for supported members and limits.",
|
||||
"keywords": [
|
||||
"tar",
|
||||
"bare-os",
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
"test [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of evaluate a condition. Full behavior is defined in packages/bare-os-coreutils/src/test.js.",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "-e, -a", "meaning": "[Issue 7 test] Path exists." },
|
||||
{ "flag": "-f, -d", "meaning": "[Issue 7 test] File or directory." },
|
||||
{ "flag": "-eq, -ne, …", "meaning": "[Issue 7 test] Integer compares when both operands are decimal." }
|
||||
],
|
||||
"keywords": [
|
||||
"test",
|
||||
"bare-os",
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
"true [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of return true value. Full behavior is defined in packages/bare-os-coreutils/src/true.js.",
|
||||
"options": [],
|
||||
"options": [
|
||||
{ "flag": "(none required)", "meaning": "[Issue 7 true] Exits 0; ignores operands." }
|
||||
],
|
||||
"keywords": [
|
||||
"true",
|
||||
"bare-os",
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"description": "Build JS /bin utilities for bare-operating-system (concat + stage to kernel/)",
|
||||
"scripts": {
|
||||
"build": "node ./scripts/ensure-man-pages.mjs && node ./build.mjs",
|
||||
"test": "node ./test/help-bin-list.test.mjs && node ./test/edit-key-parse.test.mjs && node ./test/edit-teardown.test.mjs && node ./test/baretop-bundle.test.mjs && node ./test/baretop-fixture.test.mjs && node ./test/posix-test-int-compare.test.mjs && node ./test/awk-sed-posix-smoke.test.mjs && node ./test/xattr-acl-utils.test.mjs"
|
||||
"test": "node ./test/help-bin-list.test.mjs && node ./test/edit-key-parse.test.mjs && node ./test/edit-teardown.test.mjs && node ./test/baretop-bundle.test.mjs && node ./test/baretop-fixture.test.mjs && node ./test/posix-test-int-compare.test.mjs && node ./test/awk-sed-posix-smoke.test.mjs && node ./test/xattr-acl-utils.test.mjs && node ./test/xcu-issue7-sweep.test.mjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { COREUTILS_COMMANDS, MAN_EXTRA_PAGES } from '../lib/commands.mjs'
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const pagesDir = join(__dirname, '../man/pages')
|
||||
|
||||
/** Commands whose man pages are explicitly marked stub/unsupported (keep empty in production). */
|
||||
const STUB = new Set()
|
||||
|
||||
const POSIX_TITLE = {
|
||||
|
||||
@@ -32,6 +32,22 @@ async function run(ctx, argv) {
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
const rbuf = await ctx.vfs.readFile('/proc/bare_os_resources')
|
||||
if (rbuf) {
|
||||
const j = JSON.parse(ctx.b4a.toString(rbuf))
|
||||
const sv = j && j.statvfs
|
||||
if (sv && typeof sv.f_blocks === 'number' && typeof sv.f_bfree === 'number') {
|
||||
const bsize = typeof sv.f_bsize === 'number' ? sv.f_bsize : 4096
|
||||
totalK = Math.max(1024, Math.ceil((sv.f_blocks * bsize) / 1024))
|
||||
const freeB = sv.f_bavail ?? sv.f_bfree
|
||||
const freeKFromStat = Math.max(0, Math.ceil((freeB * bsize) / 1024))
|
||||
usedK = Math.max(0, totalK - freeKFromStat)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
const freeK = Math.max(0, totalK - usedK)
|
||||
const pct =
|
||||
totalK > 0 ? Math.min(100, Math.round((usedK / totalK) * 100)) : 0
|
||||
|
||||
@@ -11,7 +11,7 @@ async function run(ctx, argv) {
|
||||
break
|
||||
}
|
||||
if (a === '-l' || a === '--list') {
|
||||
ctx.console.log('HUP INT KILL TERM 0')
|
||||
ctx.console.log('HUP INT KILL TERM PIPE CHLD USR1 USR2 0')
|
||||
return
|
||||
}
|
||||
if (a === '-s' || a === '--signal') {
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Brittle edge checks for high-traffic utilities (Issue 7 traceability).
|
||||
*/
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import test from 'brittle'
|
||||
import b4a from 'b4a'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
async function loadBin(name) {
|
||||
const runtime = await readFile(
|
||||
path.join(__dirname, '../lib/runtime.js'),
|
||||
'utf8'
|
||||
)
|
||||
const body = await readFile(
|
||||
path.join(__dirname, `../src/${name}.js`),
|
||||
'utf8'
|
||||
)
|
||||
return new AsyncFunction(
|
||||
'ctx',
|
||||
'argv',
|
||||
`${runtime}\n${body}\nif (typeof run === 'function') return await run(ctx, argv)\n`
|
||||
)
|
||||
}
|
||||
|
||||
test('cp -u skips newer destination', async (t) => {
|
||||
const run = await loadBin('cp')
|
||||
const store = {
|
||||
files: {
|
||||
'/src': {
|
||||
stat: { mode: 0o644, type: 'file', mtimeMs: 100 },
|
||||
body: b4a.from('a')
|
||||
},
|
||||
'/dst': {
|
||||
stat: { mode: 0o644, type: 'file', mtimeMs: 200 },
|
||||
body: b4a.from('b')
|
||||
}
|
||||
}
|
||||
}
|
||||
const ctx = {
|
||||
b4a,
|
||||
exitCode: 0,
|
||||
console: { log: () => {}, error: () => {} },
|
||||
vfs: {
|
||||
async lstat(p) {
|
||||
const e = store.files[p]
|
||||
return e ? e.stat : null
|
||||
},
|
||||
async readFile(p) {
|
||||
const e = store.files[p]
|
||||
return e ? e.body : null
|
||||
},
|
||||
async writeFile() {
|
||||
throw new Error('should not write when -u skips')
|
||||
}
|
||||
}
|
||||
}
|
||||
await run(ctx, ['cp', '-u', '/src', '/dst'])
|
||||
t.is(ctx.exitCode, 0)
|
||||
t.is(b4a.toString(store.files['/dst'].body), 'b')
|
||||
})
|
||||
|
||||
test('test -e is true for existing file', async (t) => {
|
||||
const run = await loadBin('test')
|
||||
let code = 1
|
||||
const ctx = {
|
||||
exitCode: 0,
|
||||
console: { log: () => {}, error: () => {} },
|
||||
vfs: {
|
||||
async stat() {
|
||||
return { type: 'file' }
|
||||
}
|
||||
}
|
||||
}
|
||||
await run(ctx, ['test', '-e', '/x'])
|
||||
code = ctx.exitCode || 0
|
||||
t.is(code, 0)
|
||||
})
|
||||
|
||||
test('true exits 0', async (t) => {
|
||||
const run = await loadBin('true')
|
||||
const ctx = { exitCode: 1, console: { log: () => {}, error: () => {} } }
|
||||
await run(ctx, ['true'])
|
||||
t.is(ctx.exitCode, 0)
|
||||
})
|
||||
@@ -46,7 +46,7 @@ export const BARE_OS_FEATURE2_CRON_REBOOT_JITTER = 1 << 10
|
||||
/** Word2 bit 11: Boot-ready `subsystems.initdActiveUnits` alignment. */
|
||||
export const BARE_OS_FEATURE2_INITD_BOOT_READY_UNITS = 1 << 11
|
||||
|
||||
/** Word2 bit 12: `/proc/self/cgroups` and `/proc/net/tcp` stubs. */
|
||||
/** Word2 bit 12: `/proc/self/cgroups` and `/proc/net/tcp` synthetic Linux-compat procfs (session + swarm–backed rows). */
|
||||
export const BARE_OS_FEATURE2_PROC_CGROUPS_TCP = 1 << 12
|
||||
|
||||
/** Word2 bit 13: Bounded `vfs.watch` on allowlisted pseudo paths. */
|
||||
@@ -97,7 +97,7 @@ export const BARE_OS_FEATURE2_INITD_SUSPEND_RESUME_ORDER = 1 << 27
|
||||
/** Word2 bit 28: Timer `OnInactiveSec=` / `Persistent=` in `.timer` files. */
|
||||
export const BARE_OS_FEATURE2_TIMER_ON_INACTIVE = 1 << 28
|
||||
|
||||
/** Word2 bit 29: `/proc/net/udp` stub (with meminfo already present). */
|
||||
/** Word2 bit 29: `/proc/net/udp` synthetic Linux-compat view (logical discovery/datagram hints). */
|
||||
export const BARE_OS_FEATURE2_PROC_NET_UDP = 1 << 29
|
||||
|
||||
/** Word2 bit 30: Bounded `vfs.watch` on `/proc/bare_os_swarm` when enabled. */
|
||||
@@ -445,7 +445,7 @@ export const BARE_OS_FEATURE9_BOOT_POLICY_SURFACE = 1 << 4
|
||||
export const BARE_OS_FEATURE9_KERNEL_EXT_REGISTRY_V6 = 1 << 5
|
||||
/** Word9 bit 6: Pear/Bare bridge word 9 (stage hint, bare module probe, …). */
|
||||
export const BARE_OS_FEATURE9_PEAR_BARE_BRIDGE_EXTENDED = 1 << 6
|
||||
/** Word9 bit 7: VFS/POSIX/shell word 9 (statfs sketch, tar hardlink, crypto stub). */
|
||||
/** Word9 bit 7: VFS/POSIX/shell word 9 (Hyperdrive-backed statvfs in resources, tar hardlink, crypto staging proc). */
|
||||
export const BARE_OS_FEATURE9_VFS_POSIX_EXTENSIONS = 1 << 7
|
||||
/** Word9 bit 8: Initd / subprocess / limits word 9. */
|
||||
export const BARE_OS_FEATURE9_INITD_SUBPROCESS = 1 << 8
|
||||
@@ -491,7 +491,7 @@ export const BARE_OS_FEATURE10_BOOT_POLICY_SURFACE = 1 << 4
|
||||
export const BARE_OS_FEATURE10_KERNEL_EXT_REGISTRY_V7 = 1 << 5
|
||||
/** Word10 bit 6: Pear/Bare bridge word 10 (doctor hint, bare logger tap, …). */
|
||||
export const BARE_OS_FEATURE10_PEAR_BARE_BRIDGE_EXTENDED = 1 << 6
|
||||
/** Word10 bit 7: VFS/POSIX/shell word 10 (ssh-keygen stub, xargs -P, tar xattr). */
|
||||
/** Word10 bit 7: VFS/POSIX/shell word 10 (ssh-keygen delegate, xargs -P, tar xattr). */
|
||||
export const BARE_OS_FEATURE10_VFS_POSIX_EXTENSIONS = 1 << 7
|
||||
/** Word10 bit 8: Initd / subprocess / git worktree policy word 10. */
|
||||
export const BARE_OS_FEATURE10_INITD_SUBPROCESS = 1 << 8
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
defaultSeedCorestorePath
|
||||
} from './lib/paths.js'
|
||||
import { logPearMultisigKernelHint } from './lib/pear-multisig-hint.js'
|
||||
import { buildSeederSnapshotHintsJson } from './lib/build-seeder-snapshot-hints-json.js'
|
||||
|
||||
const _pkg = packageRootDir(import.meta.url)
|
||||
|
||||
@@ -459,7 +460,8 @@ async function main() {
|
||||
readyGuardV5Json: String(hostEnv?.BARE_OS_SEED_READY_GUARD_V5_JSON ?? ''),
|
||||
mirrorDriveCompactionV6Json: String(
|
||||
hostEnv?.BARE_OS_SEED_MIRROR_DRIVE_COMPACTION_V6_JSON ?? ''
|
||||
)
|
||||
),
|
||||
snapshotHintsJson: buildSeederSnapshotHintsJson(hostEnv)
|
||||
}
|
||||
|
||||
const swarm = new Hyperswarm()
|
||||
|
||||
@@ -121,6 +121,22 @@ async function run(ctx, argv) {
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
const rbuf = await ctx.vfs.readFile('/proc/bare_os_resources')
|
||||
if (rbuf) {
|
||||
const j = JSON.parse(ctx.b4a.toString(rbuf))
|
||||
const sv = j && j.statvfs
|
||||
if (sv && typeof sv.f_blocks === 'number' && typeof sv.f_bfree === 'number') {
|
||||
const bsize = typeof sv.f_bsize === 'number' ? sv.f_bsize : 4096
|
||||
totalK = Math.max(1024, Math.ceil((sv.f_blocks * bsize) / 1024))
|
||||
const freeB = sv.f_bavail ?? sv.f_bfree
|
||||
const freeKFromStat = Math.max(0, Math.ceil((freeB * bsize) / 1024))
|
||||
usedK = Math.max(0, totalK - freeKFromStat)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
const freeK = Math.max(0, totalK - usedK)
|
||||
const pct =
|
||||
totalK > 0 ? Math.min(100, Math.round((usedK / totalK) * 100)) : 0
|
||||
|
||||
@@ -100,7 +100,7 @@ async function run(ctx, argv) {
|
||||
break
|
||||
}
|
||||
if (a === '-l' || a === '--list') {
|
||||
ctx.console.log('HUP INT KILL TERM 0')
|
||||
ctx.console.log('HUP INT KILL TERM PIPE CHLD USR1 USR2 0')
|
||||
return
|
||||
}
|
||||
if (a === '-s' || a === '--signal') {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 3,
|
||||
"ctxApiVersion": "1.30.0",
|
||||
"schemaVersion": 4,
|
||||
"ctxApiVersion": "1.31.0",
|
||||
"posixProfile": {
|
||||
"id": "bare-os-posix-like",
|
||||
"version": "1.0.0"
|
||||
@@ -14,6 +14,19 @@
|
||||
"ENOENT": 2,
|
||||
"EACCES": 13
|
||||
},
|
||||
"fdModel": {
|
||||
"schema": 1,
|
||||
"note": "Integer FDs index logical VFS/IPC targets in the guest.",
|
||||
"stdio": [0, 1, 2],
|
||||
"register": "ctx.bareOsRegisterLogicalFd",
|
||||
"processTablePath": "/proc/bare_os/process_table.json",
|
||||
"processTableSchema": 3
|
||||
},
|
||||
"signalModel": {
|
||||
"schema": 1,
|
||||
"note": "ctx.bareOsSendSignal delivers to synthetic pids.",
|
||||
"names": ["HUP", "INT", "KILL", "TERM"]
|
||||
},
|
||||
"caps": {
|
||||
"note": "example"
|
||||
},
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"version": 1,
|
||||
"bundles": [
|
||||
{
|
||||
"path": "/lib/bare/bundles/b4a.js",
|
||||
"keys": [
|
||||
"b4a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/safetyCatch.js",
|
||||
"keys": [
|
||||
"safetyCatch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/b4a.js",
|
||||
"keys": [
|
||||
"b4a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
|
||||
"keys": [
|
||||
@@ -25,18 +25,18 @@
|
||||
"compactEncoding"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/protomux.js",
|
||||
"keys": [
|
||||
"protomux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUrl.js",
|
||||
"keys": [
|
||||
"bareUrl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/protomux.js",
|
||||
"keys": [
|
||||
"protomux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePath.js",
|
||||
"keys": [
|
||||
@@ -61,12 +61,6 @@
|
||||
"bareAbort"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAnsiEscapes.js",
|
||||
"keys": [
|
||||
"bareAnsiEscapes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAbortController.js",
|
||||
"keys": [
|
||||
@@ -79,6 +73,12 @@
|
||||
"bareReadline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAnsiEscapes.js",
|
||||
"keys": [
|
||||
"bareAnsiEscapes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAddonResolve.js",
|
||||
"keys": [
|
||||
@@ -97,6 +97,12 @@
|
||||
"bareAppKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/fetch.js",
|
||||
"keys": [
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAsyncHooks.js",
|
||||
"keys": [
|
||||
@@ -121,36 +127,24 @@
|
||||
"bareAtomics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/fetch.js",
|
||||
"keys": [
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBmp.js",
|
||||
"keys": [
|
||||
"bareBmp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundle.js",
|
||||
"keys": [
|
||||
"bareBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleCompile.js",
|
||||
"keys": [
|
||||
"bareBundleCompile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBuffer.js",
|
||||
"keys": [
|
||||
"bareBuffer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleCompile.js",
|
||||
"keys": [
|
||||
"bareBundleCompile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBluetoothApple.js",
|
||||
"keys": [
|
||||
@@ -158,9 +152,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleEvaluate.js",
|
||||
"path": "/lib/bare/bundles/bareBundle.js",
|
||||
"keys": [
|
||||
"bareBundleEvaluate"
|
||||
"bareBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -170,9 +164,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareConsole.js",
|
||||
"path": "/lib/bare/bundles/bareBundleEvaluate.js",
|
||||
"keys": [
|
||||
"bareConsole"
|
||||
"bareBundleEvaluate"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -188,9 +182,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDelta.js",
|
||||
"path": "/lib/bare/bundles/bareConsole.js",
|
||||
"keys": [
|
||||
"bareDelta"
|
||||
"bareConsole"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -206,15 +200,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDiagnosticsChannel.js",
|
||||
"path": "/lib/bare/bundles/bareDelta.js",
|
||||
"keys": [
|
||||
"bareDiagnosticsChannel"
|
||||
"bareDelta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDns.js",
|
||||
"path": "/lib/bare/bundles/bareDiagnosticsChannel.js",
|
||||
"keys": [
|
||||
"bareDns"
|
||||
"bareDiagnosticsChannel"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -224,9 +218,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareExif.js",
|
||||
"path": "/lib/bare/bundles/bareDns.js",
|
||||
"keys": [
|
||||
"bareExif"
|
||||
"bareDns"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -235,42 +229,36 @@
|
||||
"bareDgram"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpeg.js",
|
||||
"keys": [
|
||||
"bareFfmpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareCov.js",
|
||||
"keys": [
|
||||
"bareCov"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareExif.js",
|
||||
"keys": [
|
||||
"bareExif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
|
||||
"keys": [
|
||||
"bareFfmpegEncodings"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpeg.js",
|
||||
"keys": [
|
||||
"bareFfmpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFormat.js",
|
||||
"keys": [
|
||||
"bareFormat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareGif.js",
|
||||
"keys": [
|
||||
"bareGif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFormData.js",
|
||||
"keys": [
|
||||
"bareFormData"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFileLogger.js",
|
||||
"keys": [
|
||||
@@ -278,21 +266,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFs.js",
|
||||
"path": "/lib/bare/bundles/bareFormData.js",
|
||||
"keys": [
|
||||
"bareFs"
|
||||
"bareFormData"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttpParser.js",
|
||||
"path": "/lib/bare/bundles/bareGif.js",
|
||||
"keys": [
|
||||
"bareHttpParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHeif.js",
|
||||
"keys": [
|
||||
"bareHeif"
|
||||
"bareGif"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -301,12 +283,24 @@
|
||||
"bareGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHeif.js",
|
||||
"keys": [
|
||||
"bareHeif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHrtime.js",
|
||||
"keys": [
|
||||
"bareHrtime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttpParser.js",
|
||||
"keys": [
|
||||
"bareHttpParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIco.js",
|
||||
"keys": [
|
||||
@@ -320,9 +314,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareInspect.js",
|
||||
"path": "/lib/bare/bundles/bareFs.js",
|
||||
"keys": [
|
||||
"bareInspect"
|
||||
"bareFs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -332,21 +326,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttps.js",
|
||||
"path": "/lib/bare/bundles/bareInspect.js",
|
||||
"keys": [
|
||||
"bareHttps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"keys": [
|
||||
"bareJpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIpc.js",
|
||||
"keys": [
|
||||
"bareIpc"
|
||||
"bareInspect"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -356,15 +338,27 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLogger.js",
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"keys": [
|
||||
"bareLogger"
|
||||
"bareJpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLief.js",
|
||||
"path": "/lib/bare/bundles/bareHttps.js",
|
||||
"keys": [
|
||||
"bareLief"
|
||||
"bareHttps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIpc.js",
|
||||
"keys": [
|
||||
"bareIpc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLogger.js",
|
||||
"keys": [
|
||||
"bareLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -373,12 +367,6 @@
|
||||
"bareInspector"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"keys": [
|
||||
"bareMake"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareLink.js",
|
||||
"keys": [
|
||||
@@ -386,9 +374,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModule.js",
|
||||
"path": "/lib/bare/bundles/bareLief.js",
|
||||
"keys": [
|
||||
"bareModule"
|
||||
"bareLief"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"keys": [
|
||||
"bareMake"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -404,9 +398,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModuleTraverse.js",
|
||||
"path": "/lib/bare/bundles/bareModule.js",
|
||||
"keys": [
|
||||
"bareModuleTraverse"
|
||||
"bareModule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"keys": [
|
||||
"bareDev"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -428,15 +428,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"path": "/lib/bare/bundles/bareModuleTraverse.js",
|
||||
"keys": [
|
||||
"bareDev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMedia.js",
|
||||
"keys": [
|
||||
"bareMedia"
|
||||
"bareModuleTraverse"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -445,6 +439,12 @@
|
||||
"bareOpen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareOs.js",
|
||||
"keys": [
|
||||
"bareOs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNet.js",
|
||||
"keys": [
|
||||
@@ -452,9 +452,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareOs.js",
|
||||
"path": "/lib/bare/bundles/bareMedia.js",
|
||||
"keys": [
|
||||
"bareOs"
|
||||
"bareMedia"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -475,18 +475,18 @@
|
||||
"barePack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePackDrive.js",
|
||||
"keys": [
|
||||
"barePackDrive"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePipe.js",
|
||||
"keys": [
|
||||
"barePipe"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePackDrive.js",
|
||||
"keys": [
|
||||
"barePackDrive"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePunycode.js",
|
||||
"keys": [
|
||||
@@ -499,24 +499,18 @@
|
||||
"barePrebuild"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQuerystring.js",
|
||||
"keys": [
|
||||
"bareQuerystring"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"keys": [
|
||||
"bareProcess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNodeRuntime.js",
|
||||
"keys": [
|
||||
"bareNodeRuntime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQuerystring.js",
|
||||
"keys": [
|
||||
"bareQuerystring"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
|
||||
"keys": [
|
||||
@@ -529,6 +523,12 @@
|
||||
"bareRealm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"keys": [
|
||||
"bareProcess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRuntime.js",
|
||||
"keys": [
|
||||
@@ -542,9 +542,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSemver.js",
|
||||
"path": "/lib/bare/bundles/bareSdl.js",
|
||||
"keys": [
|
||||
"bareSemver"
|
||||
"bareSdl"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -554,15 +554,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSdl.js",
|
||||
"path": "/lib/bare/bundles/bareSemver.js",
|
||||
"keys": [
|
||||
"bareSdl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSidecar.js",
|
||||
"keys": [
|
||||
"bareSidecar"
|
||||
"bareSemver"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -572,9 +566,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRepl.js",
|
||||
"path": "/lib/bare/bundles/bareSidecar.js",
|
||||
"keys": [
|
||||
"bareRepl"
|
||||
"bareSidecar"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -590,9 +584,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStream.js",
|
||||
"path": "/lib/bare/bundles/bareRepl.js",
|
||||
"keys": [
|
||||
"bareStream"
|
||||
"bareRepl"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -601,6 +595,12 @@
|
||||
"bareStorage"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStream.js",
|
||||
"keys": [
|
||||
"bareStream"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStdio.js",
|
||||
"keys": [
|
||||
@@ -620,15 +620,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSubprocess.js",
|
||||
"path": "/lib/bare/bundles/bareTiff.js",
|
||||
"keys": [
|
||||
"bareSubprocess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSystemLogger.js",
|
||||
"keys": [
|
||||
"bareSystemLogger"
|
||||
"bareTiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -638,21 +632,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTiff.js",
|
||||
"path": "/lib/bare/bundles/bareSystemLogger.js",
|
||||
"keys": [
|
||||
"bareTiff"
|
||||
"bareSystemLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTimers.js",
|
||||
"path": "/lib/bare/bundles/bareSubprocess.js",
|
||||
"keys": [
|
||||
"bareTimers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTpl.js",
|
||||
"keys": [
|
||||
"bareTpl"
|
||||
"bareSubprocess"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -661,6 +649,12 @@
|
||||
"bareThread"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTimers.js",
|
||||
"keys": [
|
||||
"bareTimers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTcp.js",
|
||||
"keys": [
|
||||
@@ -668,9 +662,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareType.js",
|
||||
"path": "/lib/bare/bundles/bareTpl.js",
|
||||
"keys": [
|
||||
"bareType"
|
||||
"bareTpl"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -679,12 +673,24 @@
|
||||
"bareTls"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareType.js",
|
||||
"keys": [
|
||||
"bareType"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUiKit.js",
|
||||
"keys": [
|
||||
"bareUiKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTty.js",
|
||||
"keys": [
|
||||
"bareTty"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnpack.js",
|
||||
"keys": [
|
||||
@@ -697,24 +703,6 @@
|
||||
"bareV8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTty.js",
|
||||
"keys": [
|
||||
"bareTty"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKit.js",
|
||||
"keys": [
|
||||
"bareWebKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareVm.js",
|
||||
"keys": [
|
||||
"bareVm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnionBundle.js",
|
||||
"keys": [
|
||||
@@ -727,6 +715,18 @@
|
||||
"bareWalkHandles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareVm.js",
|
||||
"keys": [
|
||||
"bareVm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKit.js",
|
||||
"keys": [
|
||||
"bareWebKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebp.js",
|
||||
"keys": [
|
||||
@@ -734,15 +734,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWhich.js",
|
||||
"path": "/lib/bare/bundles/bareWebKitGtk.js",
|
||||
"keys": [
|
||||
"bareWhich"
|
||||
"bareWebKitGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"path": "/lib/bare/bundles/bareWhich.js",
|
||||
"keys": [
|
||||
"bareV8ToIstanbul"
|
||||
"bareWhich"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -758,15 +758,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKitGtk.js",
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"keys": [
|
||||
"bareWebKitGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareXdiff.js",
|
||||
"keys": [
|
||||
"bareXdiff"
|
||||
"bareV8ToIstanbul"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -782,9 +776,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWorker.js",
|
||||
"path": "/lib/bare/bundles/bareXdiff.js",
|
||||
"keys": [
|
||||
"bareWorker"
|
||||
"bareXdiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -792,6 +786,12 @@
|
||||
"keys": [
|
||||
"bareWs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWorker.js",
|
||||
"keys": [
|
||||
"bareWorker"
|
||||
]
|
||||
}
|
||||
],
|
||||
"bundleStats": {
|
||||
@@ -1595,8 +1595,8 @@
|
||||
],
|
||||
"bundleProvenance": {
|
||||
"schemaVersion": 1,
|
||||
"generatedAt": "2026-04-05T01:31:52.568Z",
|
||||
"gitCommit": "346bb71ffe4b7d059d4e16454dc9e4afff73224b",
|
||||
"generatedAt": "2026-04-05T01:58:32.340Z",
|
||||
"gitCommit": "57ba71899bdfadc92caeb9eb8ede55d3484d9697",
|
||||
"nodeVersion": "v22.22.0",
|
||||
"bundleTier": "all",
|
||||
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"atMs": 1775352711830,
|
||||
"atMs": 1775354354273,
|
||||
"commands": [
|
||||
"arch",
|
||||
"awk",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Build `snapshotHintsJson` for `setupSeedChannel` (bare_os.snapshot_hints RPC → booter proc).
|
||||
* @param {Record<string, string | undefined> | null | undefined} hostEnv
|
||||
* @returns {string}
|
||||
*/
|
||||
export function buildSeederSnapshotHintsJson(hostEnv) {
|
||||
const e = hostEnv && typeof hostEnv === 'object' ? hostEnv : {}
|
||||
const explicit = String(e.BARE_OS_SEED_SNAPSHOT_HINTS_JSON ?? '').trim()
|
||||
if (explicit) return explicit
|
||||
const tag = String(e.BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG ?? '').trim()
|
||||
if (!tag) return ''
|
||||
return JSON.stringify({
|
||||
schema: 1,
|
||||
corestoreSnapshotTag: tag,
|
||||
source: 'BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG'
|
||||
})
|
||||
}
|
||||
@@ -7,7 +7,8 @@
|
||||
"scripts": {
|
||||
"start": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-seeder && bare index.js",
|
||||
"dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-seeder && bare index.js",
|
||||
"pear:dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-seeder && pear run --dev ."
|
||||
"pear:dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-seeder && pear run --dev .",
|
||||
"test": "node --test test/*.test.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"bare-subprocess": "^5.2.3",
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @import { test } from 'node:test'
|
||||
*/
|
||||
import assert from 'node:assert'
|
||||
import test from 'node:test'
|
||||
import { buildSeederSnapshotHintsJson } from '../lib/build-seeder-snapshot-hints-json.js'
|
||||
|
||||
test('empty env yields empty snapshotHintsJson', () => {
|
||||
assert.strictEqual(buildSeederSnapshotHintsJson({}), '')
|
||||
})
|
||||
|
||||
test('BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG becomes hints payload', () => {
|
||||
const j = buildSeederSnapshotHintsJson({
|
||||
BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG: 'release-42'
|
||||
})
|
||||
const o = JSON.parse(j)
|
||||
assert.strictEqual(o.schema, 1)
|
||||
assert.strictEqual(o.corestoreSnapshotTag, 'release-42')
|
||||
assert.strictEqual(o.source, 'BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG')
|
||||
})
|
||||
|
||||
test('BARE_OS_SEED_SNAPSHOT_HINTS_JSON wins over tag', () => {
|
||||
const want = '{"schema":9,"slots":["a"]}'
|
||||
const j = buildSeederSnapshotHintsJson({
|
||||
BARE_OS_SEED_SNAPSHOT_HINTS_JSON: want,
|
||||
BARE_OS_SEED_CORESTORE_SNAPSHOT_TAG: 'ignored'
|
||||
})
|
||||
assert.strictEqual(j, want)
|
||||
})
|
||||
@@ -259,6 +259,10 @@ Validates representative JSON under **`kernel/etc/bare-os/`** (e.g. **`boot.poli
|
||||
|
||||
Maintainer helper for release/staging workflows (see script header for intended use).
|
||||
|
||||
## Root `npm run test:bare`
|
||||
|
||||
Runs **`bare-os-protocol`** tests, **`bare-os-booter`** **`test:bare`** (**`brittle-bare`** identity slice), and **`bare-os-seeder`** **`node --test`** helpers. Full workspace coverage remains **`npm test`** (includes **`brittle-node`** booter harness + coreutils).
|
||||
|
||||
## See also
|
||||
|
||||
- Root [README.md](../README.md) — Pear + workspaces note
|
||||
|
||||
Reference in New Issue
Block a user