feat(booter): disk.os bridge, systemctl ctx API, delegates, and docs

- Add createBareOsDiskOsBridge for Hyperdrive searchLocal + whitelisted
  bare_os.* execRpc; wire disk.os after initd
- Expose ctx.bareOsRunSystemctlCli; route /bin/systemctl and journalctl
  through it (sync seeder kernel/bin)
- Implement ssh-keygen passphrase envelope (bareOsKeySchema 2, PBKDF2 +
  ChaCha20-Poly1305); add warc and archive delegates
- Extend basenc (--base32/--base64); improve hostid/users session UX
- Introduce bare-os-boot-phases, bare-os-errors; CI boot-step alignment
- Bump BARE_OS_CTX_API_VERSION to 1.28.0; update ctx d.ts and verifiers
- Add KERNEL_CONTRACT, OTA_AND_BUNDLES, PLACEHOLDER_BASELINE; handbook
  disk.os + security hooks; reference docs and CHANGELOG
This commit is contained in:
Raven Scott
2026-04-04 18:09:08 -04:00
parent 8f2e3cceb0
commit d38b6eeaac
47 changed files with 1897 additions and 547 deletions
+3
View File
@@ -33,6 +33,9 @@ The file-by-file inventory that used to live in a single monolith is now split u
- **[Documentation hub](docs/README.md)** — `docs/` tree: reference index, catalog, themes.
- **[Handbook](handbook/README.md)** — narrative architecture and operations.
- **[Developer guide](developer-guide/README.md)** — extending the image, `ctx`, coreutils, testing.
- **[Kernel architecture contract](docs/architecture/KERNEL_CONTRACT.md)** — booter vs image boundaries, boot steps, typed errors.
- **[OTA and bundles](docs/deployment/OTA_AND_BUNDLES.md)** — Bare/Pear packaging hooks for operators.
- **[Placeholder baseline (audit)](docs/audit/PLACEHOLDER_BASELINE.md)** — classified incomplete surfaces and closure notes.
- **Legacy ↔ canonical names** — [`docs/reference/naming-alias-matrix.md`](docs/reference/naming-alias-matrix.md)
---
+2
View File
@@ -14,6 +14,8 @@ This project is **experimental research software**. APIs described here follow t
**Contract checks:** changing **`bareOsCtxApiVersion`** or stock kernel feature bits should keep **`scripts/verify-ctx-api-feature-bits.mjs`** green (invoked from root **`pretest`**).
**Architecture contract (boundaries):** [`docs/architecture/KERNEL_CONTRACT.md`](../docs/architecture/KERNEL_CONTRACT.md) — booter vs guest image, **`disk.os`** RPC, boot step IDs.
---
## On this page
+3
View File
@@ -24,6 +24,9 @@ This directory is the **`docs/`** tree: reference material, JSON catalog inputs,
## Reference
- **[Reference hub](reference/README.md)** — file-level inventory (packages, kernel tree, environment appendix, data-flow diagram). Split from the former root `DOCUMENTATION.md`.
- **[Kernel architecture contract](architecture/KERNEL_CONTRACT.md)** — booter vs guest image boundaries, boot step IDs, typed errors.
- **[Audit baseline](audit/PLACEHOLDER_BASELINE.md)** — classified incomplete surfaces (incl. vendored bundles).
- **[OTA and bundles](deployment/OTA_AND_BUNDLES.md)** — Bare/Pear packaging notes for releases.
---
+35
View File
@@ -0,0 +1,35 @@
# Kernel architecture contract (stock booter + guest image)
This document is the **single overview** of how the Bare OS “kernel” is split between the **host booter** (`packages/bare-os-booter`) and the **guest system image** (`kernel/` staged to Hyperdrive). Detailed behavior lives in the handbook and developer guide; this file defines **boundaries and naming** only.
## Subsystems
| Subsystem | Owner | Responsibility |
|-----------|--------|------------------|
| **Wire + disk I/O** | Booter | Hyperswarm, Protomux, `SwarmDisk`, Corestore, Hyperdrive open/replicate |
| **VFS + policy** | Booter | `createVfs`, path classes, mounts, synthetic `/proc` |
| **Identity / vault** | Booter + bins | Session env, account file, `login` / `savevault` flows |
| **Init / services** | Booter | `bare-initd`, `systemctl` delegate, unit files |
| **Guest shell + `/bin`** | Image + booter | Hyperdrive-resident scripts; host delegates for selected CLIs |
| **Extensions** | Image | `kernel.ext.d`, manifests; resolver in booter |
| **Peer search / OS RPC** | Booter | `disk.os` after initd (`bare-os-disk-os-bridge.js`) |
## Boot steps (booter)
Canonical identifiers: `BARE_OS_BOOTER_BOOT_STEPS` in [`packages/bare-os-booter/lib/bare-os-boot-phases.js`](../../packages/bare-os-booter/lib/bare-os-boot-phases.js). Emitted in order: **`vfs`** → **`ctx`** → **`repl`** → **`initd`** → **`kernel_invoke`**.
## Context API
- Version: **`BARE_OS_CTX_API_VERSION`** in [`packages/bare-os-booter/lib/bare-os-ctx-api.js`](../../packages/bare-os-booter/lib/bare-os-ctx-api.js).
- Type hints: [`packages/bare-os-booter/lib/bare-os-ctx.d.ts`](../../packages/bare-os-booter/lib/bare-os-ctx.d.ts).
## Typed errors (for callers)
Shared error classes (stable `code` field): [`packages/bare-os-booter/lib/bare-os-errors.js`](../../packages/bare-os-booter/lib/bare-os-errors.js).
## Related docs
- [Handbook — protocol and disk](../../handbook/03-protocol-and-disk.md)
- [Handbook — booter runtime](../../handbook/04-the-booter-runtime.md)
- [Compatibility matrix](../reference/compatibility-matrix.md)
- [Placeholder baseline (audit)](../audit/PLACEHOLDER_BASELINE.md)
+51
View File
@@ -0,0 +1,51 @@
# Placeholder and incomplete-code baseline (authoritative)
This document classifies incomplete surfaces as of the kernel hardening pass. It is the reference for risk triage and closure tracking.
## Severity legend
- **P0**: Affects trust, boot, security, or remote RPC surfaces.
- **P1**: User-visible CLI or guest `/bin` behavior diverges from documented contracts.
- **P2**: Operational or developer-experience gaps.
- **P3**: Third-party generated artifacts; behavior owned by upstream Bare/Holepunch bundles.
## P0 — Host RPC and swarm disk (`disk.os`)
| Item | Location | Resolution |
| ---------------------------- | ------------------------------------------------------------------------ | ---------- |
| Empty `searchLocal` / `execRpc` | `packages/bare-os-booter/index.js` (wired via `bare-os-disk-os-bridge.js`) | Implemented: path substring search on system Hyperdrive; whitelisted `bare_os.*` RPC methods. |
## P1 — Guest `/bin` and host delegates
| Item | Location | Resolution |
| ---------------------------- | --------------------------------------------- | ---------- |
| `systemctl` / `journalctl` error-only scripts | `kernel/bin/systemctl`, `kernel/bin/journalctl` | Implemented: call `ctx.bareOsRunSystemctlCli` when present (parity with `curl`). |
| `ssh-keygen` passphrase rejection | `packages/bare-os-booter/lib/ssh-keygen-cli.js` | Implemented: PBKDF2 + ChaCha20-Poly1305 sealed envelope (`bareOsKeySchema: 2`). |
| `basenc` base16-only messaging | `packages/bare-os-coreutils/src/basenc.js` | Implemented: `--base64` / `--base32` (RFC-style) in addition to `--base16`. |
| `hostid` / `users` “stub” UX | `packages/bare-os-coreutils/src/hostid.js`, `users.js` | Implemented: stable hostid from Ed25519 public key when identity unlocked; `users` documents active session. |
| WARC / archive delegates labeled placeholder | `packages/bare-os-booter/lib/host-delegate-registry.js` | Implemented: `warc-cli.js`, `archive-cli.js` (archive maps to ustar `tar`). |
| hrpc / bundlebee / sidecar / pear_runtime_matrix | `host-delegate-registry.js` | Remain **host-wired**: `shouldDelegate` false; messages describe required host bridge (no doc-only placeholder errors for warc/archive). |
## P2 — Scripts and documentation
| Item | Location | Notes |
| ---------------------------- | --------------------------- | ----- |
| `gen-ctx-client-stub.mjs` name | `scripts/` | Generates client helper; naming is historical. |
| Man / reference “placeholder” prose | `docs/`, `kernel/share/man/` | Tracked for alignment with implemented behavior. |
## P3 — Vendored `kernel/lib/bare/bundles/*.js`
Upstream-generated IIFEs may contain `TODO` comments, `NOT_IMPLEMENTED` helpers, and abstract stream throws. These are **not** first-party kernel policy; they are rebuilt from `bare-os-bare-libs` and mirrored under `packages/bare-os-seeder/kernel/`. Closure strategy: upstream version bumps, selective excludes, or post-process policy documented in `kernel/lib/bare/README.md`.
## Subsystem matrix
| Subsystem | First-party status | Bundle / vendor |
| ----------- | ------------------ | --------------- |
| Booter / ctx | Hardened in this pass | — |
| Protocol | No TODO scan in this file | Wire contracts in `bare-os-protocol` |
| Guest kernel (`kernel/lib/boot`) | CI: `verify-runtime-no-incomplete-markers.mjs` | — |
| Coreutils | basenc / hostid / users updated | — |
## Review cadence
Re-run a full-repo scan before each release and append a dated section here when new gaps are introduced or closed.
+29
View File
@@ -0,0 +1,29 @@
# OTA updates, bundles, and reproducible artifacts
Bare OS aligns with the **Holepunch** toolchain for shipping JavaScript as **Bare bundles** and (where applicable) **Pear**-style drives. This note ties upstream packages to operator workflows.
## Upstream primitives
| Package | Role |
|---------|------|
| **bare-pack** / **bare-bundle** | Resolve module graph → single bundle artifact (`imports`, `resolutions`, addons, assets). |
| **bare-build** | Platform packaging (desktop/mobile) around Bare runtimes. |
| **bare-run** | Cross-target execution of packed graphs for CI and device labs. |
| **pear-pack** / **pear-bundle** | Pear drive staging; prebuild maps for multi-arch. |
| **pear-runtime** (+ **pear-runtime-updater**) | Embeddable OTA patterns (experimental upstream; mirror concepts in boot policy). |
## Bare OS integration
- **System image**: `kernel/` is staged to the **system Hyperdrive** by **`bare-os-seeder`**; the booter never falls back to a git checkout for production boot.
- **Ctx / API semver**: bump **`BARE_OS_CTX_API_VERSION`** when guest-visible `ctx` behavior changes; record it in [compatibility-matrix.md](../reference/compatibility-matrix.md).
- **Offline / LKG**: document **`BARE_OS_OFFLINE_LKG_BOOT`** and related env in [environment appendix](../reference/environment-and-posix-appendix.md).
## Reproducibility checklist
1. Pin workspace dependency versions (lockfile).
2. Run **`npm run pretest`** before tag (bundle kernel, verify seeder parity, manifest smoke).
3. Record **`bareOsCtxApiVersion`**, **`BARE_OS_KERNEL_FEATURE_BITS_DOC`**, and **`BARE_OS_LIFECYCLE_SCHEMA_VERSION`** in release notes (see compatibility matrix).
## Future work
Delta OTA, A/B slots, and signed rollback indices are **roadmap** items; track against [kernel program](../../handbook/11-kernel-program-and-research.md) batches and capability words.
+6
View File
@@ -12,6 +12,9 @@ This directory holds the split **file-by-file inventory** that used to live in t
| Day-to-day use | [Users manual](../../users-manual/README.md) |
| File-level inventory | This directory (`docs/reference/`) |
| JSON Schemas | [`docs/schemas/`](../schemas/) |
| Kernel contract (boundaries) | [`docs/architecture/KERNEL_CONTRACT.md`](../architecture/KERNEL_CONTRACT.md) |
| Audit baseline | [`docs/audit/PLACEHOLDER_BASELINE.md`](../audit/PLACEHOLDER_BASELINE.md) |
| OTA / bundles (operators) | [`docs/deployment/OTA_AND_BUNDLES.md`](../deployment/OTA_AND_BUNDLES.md) |
| CI / verifiers | [`scripts/README.md`](../../scripts/README.md) |
---
@@ -32,6 +35,9 @@ This directory holds the split **file-by-file inventory** that used to live in t
- **Package: bare-os-booter** (former §§12.112.9) — [Package: bare-os-booter](package-bare-os-booter.md)
- **bare-os-coreutils, tests, and seeder build hook** (former §§12.1012.12) — [bare-os-coreutils, tests, and seeder build hook](package-bare-os-coreutils-and-ci.md)
- **Architecture: end-to-end data flow** (former §13) — [Architecture: end-to-end data flow](architecture-data-flow.md)
- **Kernel architecture contract** (booter vs image, boot steps) — [KERNEL_CONTRACT.md](../architecture/KERNEL_CONTRACT.md)
- **Placeholder / stub audit baseline** — [PLACEHOLDER_BASELINE.md](../audit/PLACEHOLDER_BASELINE.md)
- **OTA and Bare/Pear bundles** — [OTA_AND_BUNDLES.md](../deployment/OTA_AND_BUNDLES.md)
- **Environment variables and POSIX appendix** (former §14, §14a) — [Environment variables and POSIX appendix](environment-and-posix-appendix.md)
- **Kernel feature bits and handshake** — [Kernel extensions](kernel-extensions.md)
- **Bits, env, `/proc`, and `ctx` map** — [Kernel capabilities index](kernel-capabilities-index.md)
+1 -1
View File
@@ -14,7 +14,7 @@ Single place to compare **protocol**, **booter `ctx` API**, **feature-bit docume
## Version artifacts
**`bareOsCtxApiVersion`** (current stock: **`1.25.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.28.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).
+1 -1
View File
@@ -110,7 +110,7 @@ Former **DOCUMENTATION.md** §§12.112.9 (runtime, VFS, shell, identity). [Re
**`runBinCommand(ctx, argv)`**
- **Host delegates first** — [`host-delegate-registry.js`](../../packages/bare-os-booter/lib/host-delegate-registry.js) registers **`git`**, **`curl`**, **`wget`**, and **`systemctl`** / **`bare-initctl`** / **`journalctl`** with **static** imports of the CLI modules (Pear-safe). Each delegate checks **`BARE_OS_DELEGATE_ALLOW`**; denied kinds exit **126**. **`curl`** and **`wget`** are Fetch-based subsets (not libcurl / full GNU wget); **`/bin/curl`** and **`/bin/wget`** on the image are **stubs** for manifest parity—see [HTTP: curl and wget](http-curl-and-wget.md).
- **Host delegates first** — [`host-delegate-registry.js`](../../packages/bare-os-booter/lib/host-delegate-registry.js) registers **`git`**, **`curl`**, **`wget`**, **`openssl`**, **`ssh-keygen`**, **`tar`**, **`systemctl`** / **`bare-initctl`** / **`journalctl`**, **`warc`**, and **`archive`** (ustar front-end) with **static** imports (Pear-safe). Each delegate checks **`BARE_OS_DELEGATE_ALLOW`**; denied kinds exit **126**. **`curl`** and **`wget`** are Fetch-based subsets (not libcurl / full GNU wget); **`/bin/curl`** and **`/bin/wget`** on the image call **`ctx.bareOsRunCurlCli`** / **`ctx.bareOsRunWgetCli`** when present—see [HTTP: curl and wget](http-curl-and-wget.md). **`/bin/systemctl`** and **`/bin/journalctl`** call **`ctx.bareOsRunSystemctlCli`** when present (same backend as the host delegate).
- If **`argv[0]`** is **`git`** (or a POSIX path whose basename is `git`, but not `./git` or `../git`), **delegates** to **`runGitCli`** in [`git-cli.js`](../../packages/bare-os-booter/lib/git-cli.js).
- If **`argv[0]`** is **`curl`** under the same basename rules, **delegates** to **`runCurlCli`** in [`curl-cli.js`](../../packages/bare-os-booter/lib/curl-cli.js).
- If **`argv[0]`** is **`wget`** under the same basename rules, **delegates** to **`runWgetCli`** in [`wget-cli.js`](../../packages/bare-os-booter/lib/wget-cli.js).
+19
View File
@@ -91,6 +91,25 @@ The **important** path for boot is **0/1** plus **Hyperdrive replication** on th
---
## Booter `disk.os` bridge (after initd)
Once **initd** has started, the stock booter assigns **`disk.os`** on **`SwarmDisk`**. Peers use the same Protomux channel (**messages 36**) to query the **running** booter—not the static seeder RAM map:
- **`searchLocal(query)`** — case-insensitive **substring** match over **system Hyperdrive** paths (recursive list, capped), returned on **message 4**.
- **`execRpc(module, method, args)`** — whitelisted **`bare_os.*`** calls only, UTF-8 result string on **message 6**:
- **`bare_os.ping`** → `pong`
- **`bare_os.ctx_api_version`** → `BARE_OS_CTX_API_VERSION`
- **`bare_os.uptime_ms`** → ms since booter VFS construction started
- **`bare_os.system_revision`** → JSON of `ctx.bareOsSystemRevision`
- **`bare_os.ipc_list`** → JSON array of FIFO channel names
- **`bare_os.service_names`** → JSON array of **initd** unit names
- **`bare_os.echo`** → JSON `{"args":[…]}` (debug)
- Unknown pairs throw **`BareOsKernelError`** with code **`BARE_OS_EXEC_RPC_UNKNOWN`** (surfaced as RPC error text).
Implementation: [`packages/bare-os-booter/lib/bare-os-disk-os-bridge.js`](../packages/bare-os-booter/lib/bare-os-disk-os-bridge.js). Architecture overview: [`docs/architecture/KERNEL_CONTRACT.md`](../docs/architecture/KERNEL_CONTRACT.md).
---
## Kernel feature bitmask (documentation)
The package **`bare-os-protocol`** exports **`lib/kernel-feature-bits.js`** (re-exported from **`index.js`**) with **versioned capability words** describing optional booter / image capabilities (word 1: **`bits`**, word 2: **`bits2`**, word 3: **`bits3`**, word 4: **`bits4`**, word 5: **`bits5`**; always **`>>> 0`** when masking). Peers see a **250-byte bitfield** on **message 2** (gossip stub; bit **0** set today). The seeder answers **`bare_os.capabilities`** over **RPC** with **`doc`** / **`featureBitsDoc`**, **`bits`**, **`bits2`**, **`bits3`**, **`bits4`**, **`bits5`**, **`protocolPackageVersion`**, **`role`**, **`protocol`** so the booter can compare before MBR read (**`BARE_OS_SEED_CAP_STRICT`** covers all non-zero words the stock booter advertises). **`bare_os.replication_status`** adds seeder-local replication hints; **`bare_os.replication_queue`** (with bounded queue / snapshot notes), **`bare_os.capability_attestation`**, **`bare_os.mbr_layout`**, **`bare_os.snapshot_hints`**, and **`bare_os.peer_firewall_stats`** are optional RPCs (hints only; guests do not verify crypto). **`mbr_layout`** / replication JSON may surface parsed **failover key slots** (MBR offsets **40** / **72**) as hex hints for operators, plus optional **staging slot**, **manifest**, **peer health**, and **firewall** sketches when the seeder implements them. Guests read dumps under **`/proc/bare_os_features`**, **`/proc/bare_os/`**, and related **`/proc`** nodes. Unknown bits should be ignored.
@@ -212,6 +212,12 @@ Prettier config: **no semicolons**, **single quotes** (`.prettierrc`).
---
## Security, ACL, and observability hooks
The booter exposes **`ctx.bareOsAclEvaluate`**, audit toggles (**`BARE_OS_AUDIT`**, **`BARE_OS_AUDIT_JSON`**), and append-only style logging under **`/var/log/`** (see environment appendix). Subsystem-oriented error classes with stable **`code`** fields live in **[`packages/bare-os-booter/lib/bare-os-errors.js`](../packages/bare-os-booter/lib/bare-os-errors.js)**. After initd, **`disk.os.execRpc`** accepts only **whitelisted** **`bare_os.*`** methods—see [Chapter 3 — `disk.os` bridge](03-protocol-and-disk.md).
---
## Further reading
- **[docs/reference/README.md](../docs/reference/README.md)** — file-by-file reference (authoritative for paths)
+2
View File
@@ -26,6 +26,8 @@ This project is **experimental research software**, not a production OS. It is l
**[docs/reference/README.md](../docs/reference/README.md)** — File-by-file inventory, environment variables, data-flow diagram.
**[docs/architecture/KERNEL_CONTRACT.md](../docs/architecture/KERNEL_CONTRACT.md)** — Single-page contract: subsystems, boot steps, `ctx` semver, typed errors.
**[developer-guide/README.md](../developer-guide/README.md)** — How to write `run(ctx, argv)` / `start(ctx)`, extend `/bin`, and test under Pear.
**[Kernel extensions](../docs/reference/kernel-extensions.md)** — Kernel feature bitmask, seed-channel RPC, and capability bits.
+192 -19
View File
@@ -87,6 +87,8 @@ function bareOsEmitRaw(ctx, chunk) {
return false
}
const B32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
function bareHexEncode(u8) {
let s = ''
for (let i = 0; i < u8.length; i++) {
@@ -106,16 +108,94 @@ function bareHexDecode(s) {
return out
}
function bareB32EncodeBytes(u8) {
let out = ''
let i = 0
let buf = 0
let bits = 0
for (; i < u8.length; i++) {
buf = (buf << 8) | u8[i]
bits += 8
while (bits >= 5) {
bits -= 5
out += B32[(buf >> bits) & 31]
}
}
if (bits > 0) out += B32[(buf << (5 - bits)) & 31]
while (out.length % 8 !== 0) out += '='
return out
}
function bareB32DecodeToU8(s) {
const t = String(s).replace(/\s+/g, '').replace(/=+$/, '')
let buf = 0
let bits = 0
const bytes = []
for (let i = 0; i < t.length; i++) {
const c = t[i]
const v = B32.indexOf(c)
if (v < 0) throw new Error('invalid base32 character')
buf = (buf << 5) | v
bits += 5
if (bits >= 8) {
bits -= 8
bytes.push((buf >> bits) & 255)
}
}
return new Uint8Array(bytes)
}
function bareB64EncodeBytes(u8) {
const B =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
let out = ''
let i = 0
for (; i + 2 < u8.length; i += 3) {
const n = (u8[i] << 16) | (u8[i + 1] << 8) | u8[i + 2]
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + B[(n >> 6) & 63] + B[n & 63]
}
const rest = u8.length - i
if (rest === 1) {
const n = u8[i] << 16
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + '=='
} else if (rest === 2) {
const n = (u8[i] << 16) | (u8[i + 1] << 8)
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + B[(n >> 6) & 63] + '='
}
return out
}
function bareB64DecodeToU8(s) {
const t = String(s).replace(/\s+/g, '')
if (typeof globalThis.Buffer !== 'undefined') {
return new Uint8Array(globalThis.Buffer.from(t, 'base64'))
}
if (typeof globalThis.atob === 'function') {
const bin = globalThis.atob(t)
const out = new Uint8Array(bin.length)
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i) & 255
return out
}
throw new Error('base64 decode requires Buffer or atob')
}
async function run(ctx, argv) {
let decode = false
let base16 = false
let base32 = false
let base64 = false
let wrap = 0
const paths = []
for (let i = 1; i < argv.length; i++) {
const a = argv[i]
if (a === '-h' || a === '--help') {
ctx.console.log(
'usage: basenc --base16 [-d] [FILE]\n' +
'Encode or decode hex (Base16). Other bases are not implemented.'
'usage: basenc [--base16 | --base32 | --base64] [-d] [-w COLS] [FILE]\n' +
' --base16 hex (default when no base flag)\n' +
' --base32 RFC 4648 Base32\n' +
' --base64 RFC 4648 Base64\n' +
' -d decode from text to raw bytes (stdout)\n' +
' -w COLS wrap encoded output (base64/base32 only; 0 = no wrap)'
)
ctx.exitCode = 0
return
@@ -128,6 +208,19 @@ async function run(ctx, argv) {
base16 = true
continue
}
if (a === '--base32') {
base32 = true
continue
}
if (a === '--base64') {
base64 = true
continue
}
if ((a === '-w' || a === '--wrap') && argv[i + 1]) {
wrap = Number.parseInt(argv[++i], 10)
if (!Number.isFinite(wrap) || wrap < 0) wrap = 0
continue
}
if (a.startsWith('-')) {
ctx.console.error('basenc: unsupported option ' + a)
ctx.exitCode = 1
@@ -135,11 +228,15 @@ async function run(ctx, argv) {
}
paths.push(a)
}
if (!base16) {
ctx.console.error('basenc: requires --base16')
const modeCount = (base16 ? 1 : 0) + (base32 ? 1 : 0) + (base64 ? 1 : 0)
if (modeCount > 1) {
ctx.console.error('basenc: specify at most one of --base16, --base32, --base64')
ctx.exitCode = 1
return
}
if (modeCount === 0) base16 = true
const b4 = ctx.b4a
let buf
if (!paths.length || paths[0] === '-') {
@@ -153,23 +250,99 @@ async function run(ctx, argv) {
}
buf = b instanceof Uint8Array ? b : new Uint8Array(b)
}
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareHexDecode(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
if (base16) {
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareHexDecode(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
ctx.console.log(bareHexEncode(buf))
return
}
ctx.console.log(bareHexEncode(buf))
if (base32) {
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareB32DecodeToU8(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
let enc = bareB32EncodeBytes(buf)
if (wrap > 0) {
const lines = []
for (let i = 0; i < enc.length; i += wrap) {
lines.push(enc.slice(i, i + wrap))
}
enc = lines.join('\n')
}
ctx.console.log(enc)
return
}
if (base64) {
if (decode) {
const text = new TextDecoder().decode(buf)
let raw
try {
raw = bareB64DecodeToU8(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
let enc
if (typeof globalThis.btoa === 'function') {
let s = ''
const step = 0x8000
for (let i = 0; i < buf.length; i += step) {
const chunk = buf.subarray(i, i + step)
s += String.fromCharCode.apply(null, chunk)
}
enc = globalThis.btoa(s)
} else {
enc = bareB64EncodeBytes(buf)
}
if (wrap > 0) {
const lines = []
for (let i = 0; i < enc.length; i += wrap) {
lines.push(enc.slice(i, i + wrap))
}
enc = lines.join('\n')
}
ctx.console.log(enc)
}
}
+17 -1
View File
@@ -90,7 +90,9 @@ function bareOsEmitRaw(ctx, chunk) {
async function run(ctx, argv) {
for (let i = 1; i < argv.length; i++) {
if (argv[i] === '-h' || argv[i] === '--help') {
ctx.console.log('usage: hostid\nPrint a numeric host identifier (session-derived stub).')
ctx.console.log(
'usage: hostid\nPrint an 8-digit hex host identifier: HOSTID env, else identity public key hash, else session-derived.'
)
return
}
if (argv[i].startsWith('-')) {
@@ -104,6 +106,20 @@ async function run(ctx, argv) {
ctx.console.log(e.HOSTID.toLowerCase())
return
}
const id = ctx.identity
const pk =
id &&
id.state === 'unlocked' &&
id.publicKey instanceof Uint8Array &&
id.publicKey.length
? id.publicKey
: null
if (pk) {
let h = 0
for (let i = 0; i < pk.length; i++) h = (Math.imul(31, h) + pk[i]) >>> 0
ctx.console.log(h.toString(16).padStart(8, '0'))
return
}
const seed = e.BARE_OS_SESSION_ID || e.HOSTNAME || 'bare-os'
let h = 0
for (let i = 0; i < seed.length; i++)
+6 -3
View File
@@ -1,8 +1,11 @@
/* BARE_OS_BIN_API 1.0.0 — stub; booter delegates to systemctl-cli (kernel-runner). */
/** Booter delegates journalctl to systemctl-cli.js (kernel-runner). */
/* BARE_OS_BIN_API 1.0.0 — delegates to booter systemctl-cli when ctx exposes bareOsRunSystemctlCli. */
async function run(ctx, argv) {
if (typeof ctx.bareOsRunSystemctlCli === 'function') {
await ctx.bareOsRunSystemctlCli(argv)
return
}
ctx.console.error(
'journalctl: not executed in host booter (delegation missing)'
'journalctl: ctx.bareOsRunSystemctlCli missing — run under host booter / upgrade ctx API'
)
ctx.exitCode = 1
}
+6 -3
View File
@@ -1,8 +1,11 @@
/* BARE_OS_BIN_API 1.0.0 — stub; booter delegates to systemctl-cli (kernel-runner). */
/** Booter delegates systemctl to systemctl-cli.js (kernel-runner). */
/* BARE_OS_BIN_API 1.0.0 — delegates to booter systemctl-cli when ctx exposes bareOsRunSystemctlCli. */
async function run(ctx, argv) {
if (typeof ctx.bareOsRunSystemctlCli === 'function') {
await ctx.bareOsRunSystemctlCli(argv)
return
}
ctx.console.error(
'systemctl: not executed in host booter (delegation missing)'
'systemctl: ctx.bareOsRunSystemctlCli missing — run under host booter / upgrade ctx API'
)
ctx.exitCode = 1
}
+3 -1
View File
@@ -90,7 +90,9 @@ function bareOsEmitRaw(ctx, chunk) {
async function run(ctx, argv) {
for (let i = 1; i < argv.length; i++) {
if (argv[i] === '-h' || argv[i] === '--help') {
ctx.console.log('usage: users\nPrint login names (single-session stub).')
ctx.console.log(
'usage: users\nPrint login names for the active Bare OS session (USER / LOGNAME from VFS env).'
)
return
}
if (argv[i].startsWith('-')) {
+184 -184
View File
@@ -2,9 +2,9 @@
"version": 1,
"bundles": [
{
"path": "/lib/bare/bundles/safetyCatch.js",
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
"keys": [
"safetyCatch"
"hypercoreIdEncoding"
]
},
{
@@ -14,9 +14,9 @@
]
},
{
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
"path": "/lib/bare/bundles/safetyCatch.js",
"keys": [
"hypercoreIdEncoding"
"safetyCatch"
]
},
{
@@ -25,6 +25,12 @@
"compactEncoding"
]
},
{
"path": "/lib/bare/bundles/protomux.js",
"keys": [
"protomux"
]
},
{
"path": "/lib/bare/bundles/bareUrl.js",
"keys": [
@@ -32,9 +38,9 @@
]
},
{
"path": "/lib/bare/bundles/protomux.js",
"path": "/lib/bare/bundles/bareEvents.js",
"keys": [
"protomux"
"bareEvents"
]
},
{
@@ -49,24 +55,12 @@
"barePath"
]
},
{
"path": "/lib/bare/bundles/bareEvents.js",
"keys": [
"bareEvents"
]
},
{
"path": "/lib/bare/bundles/bareAbort.js",
"keys": [
"bareAbort"
]
},
{
"path": "/lib/bare/bundles/bareAbortController.js",
"keys": [
"bareAbortController"
]
},
{
"path": "/lib/bare/bundles/bareAnsiEscapes.js",
"keys": [
@@ -74,9 +68,9 @@
]
},
{
"path": "/lib/bare/bundles/bareReadline.js",
"path": "/lib/bare/bundles/bareAbortController.js",
"keys": [
"bareReadline"
"bareAbortController"
]
},
{
@@ -92,9 +86,9 @@
]
},
{
"path": "/lib/bare/bundles/bareApk.js",
"path": "/lib/bare/bundles/bareReadline.js",
"keys": [
"bareApk"
"bareReadline"
]
},
{
@@ -104,9 +98,9 @@
]
},
{
"path": "/lib/bare/bundles/fetch.js",
"path": "/lib/bare/bundles/bareAppKit.js",
"keys": [
"fetch"
"bareAppKit"
]
},
{
@@ -122,9 +116,15 @@
]
},
{
"path": "/lib/bare/bundles/bareAppKit.js",
"path": "/lib/bare/bundles/bareApk.js",
"keys": [
"bareAppKit"
"bareApk"
]
},
{
"path": "/lib/bare/bundles/fetch.js",
"keys": [
"fetch"
]
},
{
@@ -140,9 +140,9 @@
]
},
{
"path": "/lib/bare/bundles/bareBluetoothApple.js",
"path": "/lib/bare/bundles/bareBundle.js",
"keys": [
"bareBluetoothApple"
"bareBundle"
]
},
{
@@ -152,9 +152,9 @@
]
},
{
"path": "/lib/bare/bundles/bareBundle.js",
"path": "/lib/bare/bundles/bareBluetoothApple.js",
"keys": [
"bareBundle"
"bareBluetoothApple"
]
},
{
@@ -169,12 +169,6 @@
"bareBoot"
]
},
{
"path": "/lib/bare/bundles/bareDebugLog.js",
"keys": [
"bareDebugLog"
]
},
{
"path": "/lib/bare/bundles/bareConsole.js",
"keys": [
@@ -199,6 +193,12 @@
"bareDelta"
]
},
{
"path": "/lib/bare/bundles/bareDebugLog.js",
"keys": [
"bareDebugLog"
]
},
{
"path": "/lib/bare/bundles/bareDaemon.js",
"keys": [
@@ -241,12 +241,6 @@
"bareDgram"
]
},
{
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
"keys": [
"bareFfmpegEncodings"
]
},
{
"path": "/lib/bare/bundles/bareFfmpeg.js",
"keys": [
@@ -254,15 +248,9 @@
]
},
{
"path": "/lib/bare/bundles/bareGif.js",
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
"keys": [
"bareGif"
]
},
{
"path": "/lib/bare/bundles/bareFormat.js",
"keys": [
"bareFormat"
"bareFfmpegEncodings"
]
},
{
@@ -271,6 +259,12 @@
"bareFormData"
]
},
{
"path": "/lib/bare/bundles/bareFormat.js",
"keys": [
"bareFormat"
]
},
{
"path": "/lib/bare/bundles/bareFileLogger.js",
"keys": [
@@ -278,21 +272,9 @@
]
},
{
"path": "/lib/bare/bundles/bareGtk.js",
"path": "/lib/bare/bundles/bareGif.js",
"keys": [
"bareGtk"
]
},
{
"path": "/lib/bare/bundles/bareFs.js",
"keys": [
"bareFs"
]
},
{
"path": "/lib/bare/bundles/bareHeif.js",
"keys": [
"bareHeif"
"bareGif"
]
},
{
@@ -301,12 +283,30 @@
"bareHrtime"
]
},
{
"path": "/lib/bare/bundles/bareHeif.js",
"keys": [
"bareHeif"
]
},
{
"path": "/lib/bare/bundles/bareGtk.js",
"keys": [
"bareGtk"
]
},
{
"path": "/lib/bare/bundles/bareHttpParser.js",
"keys": [
"bareHttpParser"
]
},
{
"path": "/lib/bare/bundles/bareFs.js",
"keys": [
"bareFs"
]
},
{
"path": "/lib/bare/bundles/bareIco.js",
"keys": [
@@ -320,15 +320,9 @@
]
},
{
"path": "/lib/bare/bundles/bareInspect.js",
"path": "/lib/bare/bundles/bareHttps.js",
"keys": [
"bareInspect"
]
},
{
"path": "/lib/bare/bundles/bareIntl.js",
"keys": [
"bareIntl"
"bareHttps"
]
},
{
@@ -337,6 +331,12 @@
"bareHttp1"
]
},
{
"path": "/lib/bare/bundles/bareInspect.js",
"keys": [
"bareInspect"
]
},
{
"path": "/lib/bare/bundles/bareJpeg.js",
"keys": [
@@ -344,15 +344,9 @@
]
},
{
"path": "/lib/bare/bundles/bareHttps.js",
"path": "/lib/bare/bundles/bareIntl.js",
"keys": [
"bareHttps"
]
},
{
"path": "/lib/bare/bundles/bareInspector.js",
"keys": [
"bareInspector"
"bareIntl"
]
},
{
@@ -361,18 +355,24 @@
"bareIpc"
]
},
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{
"path": "/lib/bare/bundles/bareLief.js",
"keys": [
"bareLief"
]
},
{
"path": "/lib/bare/bundles/bareInspector.js",
"keys": [
"bareInspector"
]
},
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{
"path": "/lib/bare/bundles/bareLink.js",
"keys": [
@@ -385,18 +385,18 @@
"bareMake"
]
},
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{
"path": "/lib/bare/bundles/bareModuleResolve.js",
"keys": [
"bareModuleResolve"
]
},
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{
"path": "/lib/bare/bundles/bareModule.js",
"keys": [
@@ -451,12 +451,6 @@
"bareMedia"
]
},
{
"path": "/lib/bare/bundles/barePack.js",
"keys": [
"barePack"
]
},
{
"path": "/lib/bare/bundles/barePerformance.js",
"keys": [
@@ -470,9 +464,9 @@
]
},
{
"path": "/lib/bare/bundles/barePipe.js",
"path": "/lib/bare/bundles/barePack.js",
"keys": [
"barePipe"
"barePack"
]
},
{
@@ -482,15 +476,15 @@
]
},
{
"path": "/lib/bare/bundles/bareNodeRuntime.js",
"path": "/lib/bare/bundles/barePipe.js",
"keys": [
"bareNodeRuntime"
"barePipe"
]
},
{
"path": "/lib/bare/bundles/barePrebuild.js",
"path": "/lib/bare/bundles/bareNodeRuntime.js",
"keys": [
"barePrebuild"
"bareNodeRuntime"
]
},
{
@@ -499,18 +493,24 @@
"barePunycode"
]
},
{
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareDev"
]
},
{
"path": "/lib/bare/bundles/bareQuerystring.js",
"keys": [
"bareQuerystring"
]
},
{
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
"keys": [
"bareQueueMicrotask"
]
},
{
"path": "/lib/bare/bundles/barePrebuild.js",
"keys": [
"barePrebuild"
]
},
{
"path": "/lib/bare/bundles/bareRealm.js",
"keys": [
@@ -518,9 +518,9 @@
]
},
{
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareQueueMicrotask"
"bareDev"
]
},
{
@@ -553,12 +553,6 @@
"bareSemver"
]
},
{
"path": "/lib/bare/bundles/bareRpc.js",
"keys": [
"bareRpc"
]
},
{
"path": "/lib/bare/bundles/bareRepl.js",
"keys": [
@@ -566,9 +560,9 @@
]
},
{
"path": "/lib/bare/bundles/bareRun.js",
"path": "/lib/bare/bundles/bareRpc.js",
"keys": [
"bareRun"
"bareRpc"
]
},
{
@@ -583,12 +577,24 @@
"bareSidecar"
]
},
{
"path": "/lib/bare/bundles/bareRun.js",
"keys": [
"bareRun"
]
},
{
"path": "/lib/bare/bundles/bareStringDecoder.js",
"keys": [
"bareStringDecoder"
]
},
{
"path": "/lib/bare/bundles/bareStdio.js",
"keys": [
"bareStdio"
]
},
{
"path": "/lib/bare/bundles/bareStorage.js",
"keys": [
@@ -602,9 +608,9 @@
]
},
{
"path": "/lib/bare/bundles/bareStdio.js",
"path": "/lib/bare/bundles/bareStructuredClone.js",
"keys": [
"bareStdio"
"bareStructuredClone"
]
},
{
@@ -613,36 +619,12 @@
"bareSvg"
]
},
{
"path": "/lib/bare/bundles/bareStructuredClone.js",
"keys": [
"bareStructuredClone"
]
},
{
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareSystemLogger"
]
},
{
"path": "/lib/bare/bundles/bareSubprocess.js",
"keys": [
"bareSubprocess"
]
},
{
"path": "/lib/bare/bundles/bareTcp.js",
"keys": [
"bareTcp"
]
},
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{
"path": "/lib/bare/bundles/bareTiff.js",
"keys": [
@@ -650,9 +632,15 @@
]
},
{
"path": "/lib/bare/bundles/bareThread.js",
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareThread"
"bareSystemLogger"
]
},
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{
@@ -662,9 +650,15 @@
]
},
{
"path": "/lib/bare/bundles/bareType.js",
"path": "/lib/bare/bundles/bareTcp.js",
"keys": [
"bareType"
"bareTcp"
]
},
{
"path": "/lib/bare/bundles/bareThread.js",
"keys": [
"bareThread"
]
},
{
@@ -674,9 +668,9 @@
]
},
{
"path": "/lib/bare/bundles/bareUiKit.js",
"path": "/lib/bare/bundles/bareType.js",
"keys": [
"bareUiKit"
"bareType"
]
},
{
@@ -685,6 +679,12 @@
"bareTls"
]
},
{
"path": "/lib/bare/bundles/bareUiKit.js",
"keys": [
"bareUiKit"
]
},
{
"path": "/lib/bare/bundles/bareTty.js",
"keys": [
@@ -697,12 +697,6 @@
"bareUnpack"
]
},
{
"path": "/lib/bare/bundles/bareVm.js",
"keys": [
"bareVm"
]
},
{
"path": "/lib/bare/bundles/bareV8.js",
"keys": [
@@ -715,6 +709,18 @@
"bareWalkHandles"
]
},
{
"path": "/lib/bare/bundles/bareVm.js",
"keys": [
"bareVm"
]
},
{
"path": "/lib/bare/bundles/bareWebKit.js",
"keys": [
"bareWebKit"
]
},
{
"path": "/lib/bare/bundles/bareUnionBundle.js",
"keys": [
@@ -727,30 +733,12 @@
"bareWebp"
]
},
{
"path": "/lib/bare/bundles/bareWebKit.js",
"keys": [
"bareWebKit"
]
},
{
"path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [
"bareWebKitGtk"
]
},
{
"path": "/lib/bare/bundles/bareUtils.js",
"keys": [
"bareUtils"
]
},
{
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
"keys": [
"bareV8ToIstanbul"
]
},
{
"path": "/lib/bare/bundles/bareWhich.js",
"keys": [
@@ -758,9 +746,9 @@
]
},
{
"path": "/lib/bare/bundles/bareXdiff.js",
"path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [
"bareXdiff"
"bareWebKitGtk"
]
},
{
@@ -770,15 +758,27 @@
]
},
{
"path": "/lib/bare/bundles/bareZlib.js",
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
"keys": [
"bareZlib"
"bareV8ToIstanbul"
]
},
{
"path": "/lib/bare/bundles/bareWs.js",
"path": "/lib/bare/bundles/bareXdiff.js",
"keys": [
"bareWs"
"bareXdiff"
]
},
{
"path": "/lib/bare/bundles/bareZmq.js",
"keys": [
"bareZmq"
]
},
{
"path": "/lib/bare/bundles/bareZlib.js",
"keys": [
"bareZlib"
]
},
{
@@ -788,9 +788,9 @@
]
},
{
"path": "/lib/bare/bundles/bareZmq.js",
"path": "/lib/bare/bundles/bareWs.js",
"keys": [
"bareZmq"
"bareWs"
]
}
],
+1 -1
View File
@@ -1,6 +1,6 @@
{
"schema": 1,
"atMs": 1775339424020,
"atMs": 1775340363610,
"commands": [
"arch",
"awk",
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -15,7 +15,7 @@
"sync:bare-manifest": "node scripts/sync-bare-module-manifest-from-catalog.mjs",
"smoke:bare-manifest": "node scripts/smoke-bare-manifest-imports.mjs",
"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/gen-ctx-client-stub.mjs > /dev/null && 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-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",
"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-booter-boot-steps-alignment.mjs && node scripts/gen-ctx-client-stub.mjs > /dev/null && 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-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",
"verify-kernel-seeder": "node scripts/verify-kernel-seeder-parity.mjs",
"release-checklist": "node scripts/release-checklist.mjs",
+1
View File
@@ -12,6 +12,7 @@ Authoritative **version alignment** with protocol and telemetry schema numbers l
| Version | Booter (workspace) | Notes |
| ------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 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. |
| 1.23.0 | 0.1.0 | Operator program snapshot: **`/proc/bare_os/giant_phase_program.json`** (+ flat alias), **`bareOsReadBareTopSnapshot`** + **`baretop`** proc entry; stock kernel **`BARE_OS_BOOT_SAFE_MODE`**, boot transaction journal + checkpoint under **`/run/bare-os/`**; **`kernel.ext.d`** **`requires`** / **`after`** / **`before`** ordering; optional **`subsystems.kernel.giantPhase`** on **`bareOsPublishBootReady`**. Governance doc since renamed to **`developer-guide/kernel-program.md`**. |
+13 -8
View File
@@ -59,6 +59,8 @@ import { runWgetCli } from './lib/wget-cli.js'
import { runOpensslCli } from './lib/openssl-cli.js'
import { runSshKeygenCli } from './lib/ssh-keygen-cli.js'
import { runTarCli } from './lib/tar-cli.js'
import { runSystemctlCli } from './lib/systemctl-cli.js'
import { createBareOsDiskOsBridge } from './lib/bare-os-disk-os-bridge.js'
import { verifyBootManifestEd25519 } from '#bare-os-boot-manifest-sig'
import { getBareInitdJournalNdjson } from './lib/bare-initd-journal.js'
import { createBareOsSandboxContext } from './lib/bare-os-sandbox.js'
@@ -2900,6 +2902,10 @@ async function executeKernel(disk, store, swarm, initSource) {
async bareOsRunTarCli(argv) {
return runTarCli(ctx, argv)
},
/** systemctl, bare-initctl, journalctl (bare-initd backend). */
async bareOsRunSystemctlCli(argv) {
return runSystemctlCli(ctx, argv)
},
bareOsEmitPearStageHint(payload = {}) {
if (typeof globalThis.process?.emit !== 'function') return false
try {
@@ -3789,14 +3795,13 @@ async function executeKernel(disk, store, swarm, initSource) {
emitBooterBootPhase('initd')
disk.os = {
async searchLocal() {
return []
},
async execRpc() {
return ''
}
}
disk.os = createBareOsDiskOsBridge({
drive: disk.drive,
bareOsIpc,
ctxApiVersion: BARE_OS_CTX_API_VERSION,
systemRevision: ctx.bareOsSystemRevision,
bootStartedMs
})
emitBooterBootPhase('kernel_invoke')
@@ -0,0 +1,64 @@
/**
* BSD-style `archive` front-end to the stock ustar `tar` delegate (create/list/extract).
* Maps common `archive c|t|x` invocations to `tar -cf|-tf|-xf`.
*/
import { runTarCli } from './tar-cli.js'
/**
* @param {Record<string, unknown>} ctx
* @param {string[]} argv argv[0] is `archive`
*/
export async function runArchiveCli(ctx, argv) {
const args = argv.slice(1)
if (
!args.length ||
args[0] === '-h' ||
args[0] === '--help' ||
args[0] === 'help'
) {
ctx.console.log(
'usage: archive c ARCHIVE PATH [PATH...]\n' +
' archive t ARCHIVE\n' +
' archive x ARCHIVE\n' +
'Maps to ustar tar -cf / -tf / -xf (see tar --help in handbook).'
)
return
}
const op = args[0]
if (op === 'c') {
const arch = args[1]
const rest = args.slice(2)
if (!arch || !rest.length) {
ctx.console.error('archive c: need ARCHIVE and at least one PATH')
ctx.exitCode = 1
return
}
await runTarCli(ctx, ['tar', '-cf', arch, ...rest])
return
}
if (op === 't') {
const arch = args[1]
if (!arch) {
ctx.console.error('archive t: need ARCHIVE')
ctx.exitCode = 1
return
}
await runTarCli(ctx, ['tar', '-tf', arch])
return
}
if (op === 'x') {
const arch = args[1]
if (!arch) {
ctx.console.error('archive x: need ARCHIVE')
ctx.exitCode = 1
return
}
await runTarCli(ctx, ['tar', '-xf', arch])
return
}
ctx.console.error('archive: first argument must be c, t, or x')
ctx.exitCode = 1
}
@@ -0,0 +1,19 @@
/**
* Canonical booter boot-step identifiers emitted through {@link emitBooterBootStep}
* (lifecycle / diagnostics). Keep in sync with `emitBooterBootPhase` call sites in `index.js`.
*/
export const BARE_OS_BOOTER_BOOT_STEPS = Object.freeze([
'vfs',
'ctx',
'repl',
'initd',
'kernel_invoke'
])
/**
* @param {string} step
* @returns {boolean}
*/
export function isKnownBareOsBooterBootStep(step) {
return BARE_OS_BOOTER_BOOT_STEPS.includes(String(step))
}
@@ -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.27.0'
export const BARE_OS_CTX_API_VERSION = '1.28.0'
+1
View File
@@ -203,6 +203,7 @@ export interface BareOsKernelContext {
bareOsRunOpensslCli?(argv: string[]): Promise<unknown>
bareOsRunSshKeygenCli?(argv: string[]): Promise<unknown>
bareOsRunTarCli?(argv: string[]): Promise<unknown>
bareOsRunSystemctlCli?(argv: string[]): Promise<unknown>
bareOsRegisterBareDiagnosticsTap?(
fn: (ev: Record<string, unknown>) => void
): () => void
@@ -0,0 +1,110 @@
/**
* Swarm-disk peer RPC bridge: local Hyperdrive path search and whitelisted OS RPC.
* Wired onto {@link import('./swarm-disk.js').SwarmDisk} as `disk.os` after initd bring-up.
*/
import { listBareServices } from './bare-initd.js'
import { BareOsKernelError } from './bare-os-errors.js'
const MAX_SEARCH_RESULTS = 256
/**
* @param {{
* drive: import('hyperdrive').default | null | undefined
* bareOsIpc: { list?: () => string[] } | null | undefined
* ctxApiVersion: string
* systemRevision: Readonly<{ currentId?: string; pendingId?: string; slot?: string }> | null | undefined
* bootStartedMs: number
* }} opts
*/
export function createBareOsDiskOsBridge(opts) {
return {
/**
* @param {string} query
* @returns {Promise<string[]>}
*/
async searchLocal(query) {
const drive = opts.drive
const q = String(query || '').trim().toLowerCase()
if (!q || !drive || typeof drive.list !== 'function') return []
/** @type {string[]} */
const matches = []
try {
for await (const ent of drive.list('/', { recursive: true })) {
const key = String(ent.key || '')
if (!key) continue
const norm = key.startsWith('/') ? key : `/${key}`
if (norm.toLowerCase().includes(q)) {
matches.push(norm)
if (matches.length >= MAX_SEARCH_RESULTS) break
}
}
} catch {
return matches
}
return matches
},
/**
* @param {string} module
* @param {string} method
* @param {string[]} args
* @returns {Promise<string>}
*/
async execRpc(module, method, args) {
const mod = String(module || '').trim()
const meth = String(method || '').trim()
const a = Array.isArray(args) ? args.map((x) => String(x)) : []
if (mod === 'bare_os' && meth === 'ping') return 'pong'
if (mod === 'bare_os' && meth === 'ctx_api_version') {
return String(opts.ctxApiVersion || '')
}
if (mod === 'bare_os' && meth === 'uptime_ms') {
const t = Date.now() - (Number(opts.bootStartedMs) || 0)
return String(Math.max(0, t))
}
if (mod === 'bare_os' && meth === 'system_revision') {
const rev = opts.systemRevision || {}
return JSON.stringify({
currentId: String(rev.currentId || ''),
pendingId: String(rev.pendingId || ''),
slot: String(rev.slot || '')
})
}
if (mod === 'bare_os' && meth === 'ipc_list') {
try {
const ipc = opts.bareOsIpc
const list = typeof ipc?.list === 'function' ? ipc.list() : []
return JSON.stringify(list)
} catch (e) {
return JSON.stringify({
error: (e && /** @type {Error} */ (e).message) || String(e)
})
}
}
if (mod === 'bare_os' && meth === 'service_names') {
try {
const names = listBareServices().map((s) => s.name)
return JSON.stringify(names)
} catch {
return '[]'
}
}
if (mod === 'bare_os' && meth === 'echo') {
return JSON.stringify({ args: a })
}
throw new BareOsKernelError(
'BARE_OS_EXEC_RPC_UNKNOWN',
`execRpc: unknown module/method: ${mod}.${meth}`
)
}
}
}
@@ -0,0 +1,66 @@
/**
* Typed errors for kernel / booter subsystems (stable `code` for guests and IPC).
*/
export class BareOsKernelError extends Error {
/**
* @param {string} code
* @param {string} message
* @param {unknown} [cause]
*/
constructor(code, message, cause) {
super(message)
this.name = 'BareOsKernelError'
/** @type {string} */
this.code = code
if (cause !== undefined) this.cause = cause
}
}
export class BareOsBootError extends BareOsKernelError {
/**
* @param {string} code
* @param {string} message
* @param {unknown} [cause]
*/
constructor(code, message, cause) {
super(code, message, cause)
this.name = 'BareOsBootError'
}
}
export class BareOsVfsError extends BareOsKernelError {
/**
* @param {string} code
* @param {string} message
* @param {unknown} [cause]
*/
constructor(code, message, cause) {
super(code, message, cause)
this.name = 'BareOsVfsError'
}
}
export class BareOsSecurityError extends BareOsKernelError {
/**
* @param {string} code
* @param {string} message
* @param {unknown} [cause]
*/
constructor(code, message, cause) {
super(code, message, cause)
this.name = 'BareOsSecurityError'
}
}
export class BareOsNetError extends BareOsKernelError {
/**
* @param {string} code
* @param {string} message
* @param {unknown} [cause]
*/
constructor(code, message, cause) {
super(code, message, cause)
this.name = 'BareOsNetError'
}
}
@@ -1,7 +1,7 @@
/**
* Host-backed CLI delegates (git, curl, wget, systemctl family) with optional allowlist.
* When `BARE_OS_DELEGATE_ALLOW` is unset or empty, all registered delegates are allowed.
* When set (comma-separated), only listed kinds run: `git`, `curl`, `wget`, `openssl`, `ssh-keygen`, `tar`, `systemctl`, `hrpc` (audit-only).
* When set (comma-separated), only listed kinds run: `git`, `curl`, `wget`, `openssl`, `ssh-keygen`, `tar`, `systemctl`, `warc`, `archive`, `hrpc` (audit-only), etc.
*/
import path from 'path'
@@ -10,7 +10,9 @@ import { runGitCli } from './git-cli.js'
import { runOpensslCli } from './openssl-cli.js'
import { runSystemctlCli } from './systemctl-cli.js'
import { runSshKeygenCli } from './ssh-keygen-cli.js'
import { runArchiveCli } from './archive-cli.js'
import { runTarCli } from './tar-cli.js'
import { runWarcCli } from './warc-cli.js'
import { runWgetCli } from './wget-cli.js'
/** @typedef {{ kind: string, describe: () => string, shouldDelegate: (cmd: string) => boolean, run: (ctx: Record<string, unknown>, argv: string[]) => Promise<unknown> }} BareOsHostDelegate */
@@ -107,74 +109,74 @@ export function loadBareOsHostDelegates() {
},
{
kind: 'hrpc',
describe: () => 'hrpc (capability-word-6 audit-only; no guest RPC execution)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error('hrpc delegate is audit-only; host must wire Holepunch RPC bridge')
)
}
},
{
kind: 'bundlebee',
describe: () => 'bundlebee (capability-word-8 audit-only)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error('bundlebee delegate is audit-only; host wires bundlebee-cli staging')
)
}
},
{
kind: 'warc',
describe: () => 'WARC delegate placeholder (doc-only)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error('warc delegate not implemented in stock booter (documentation placeholder)')
)
}
},
{
kind: 'archive',
describe: () => 'archive delegate placeholder (doc-only)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error('archive delegate not implemented in stock booter (documentation placeholder)')
)
}
},
{
kind: 'sidecar',
describe: () => 'sidecar resource cap (word 11 audit-only)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error('sidecar delegate is audit-only; host wires bare-sidecar bridges')
)
}
},
{
kind: 'pear_runtime_matrix',
describe: () => 'pear-runtime matrix (word 11 audit-only)',
describe: () =>
'hrpc (capability-word-6; host must expose Holepunch RPC — no stock guest execution)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error(
'pear_runtime_matrix delegate is audit-only; see ctx.bareOsPearRuntimeMatrixProbe'
'hrpc: stock booter does not execute guest Holepunch RPC; configure a host hrpc bridge or use seed RPC surfaces'
)
)
}
},
{
kind: 'bundlebee',
describe: () =>
'bundlebee (capability-word-8; host must wire bundlebee staging — not executed in stock booter)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error(
'bundlebee: stock booter has no bundlebee pipeline; host must wire bundlebee-cli staging'
)
)
}
},
{
kind: 'warc',
describe: () => 'warc (WARC 1.0 list / write-response via VFS)',
shouldDelegate(cmd) {
return matchBasename(cmd, 'warc')
},
run: (ctx, argv) => runWarcCli(ctx, argv)
},
{
kind: 'archive',
describe: () => 'archive (ustar tar compatibility front-end)',
shouldDelegate(cmd) {
return matchBasename(cmd, 'archive')
},
run: (ctx, argv) => runArchiveCli(ctx, argv)
},
{
kind: 'sidecar',
describe: () => 'sidecar resource cap (word 11; host bare-sidecar bridge required)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error(
'sidecar: stock booter does not spawn sidecars; use ctx hooks / host bare-sidecar integration'
)
)
}
},
{
kind: 'pear_runtime_matrix',
describe: () => 'pear-runtime matrix (word 11; introspect via ctx.bareOsPearRuntimeMatrixProbe)',
shouldDelegate() {
return false
},
run() {
return Promise.reject(
new Error(
'pear_runtime_matrix: use ctx.bareOsPearRuntimeMatrixProbe; no shell delegate in stock booter'
)
)
}
+46 -22
View File
@@ -3,9 +3,13 @@
* Writes OpenSSH-compatible `.pub` line + a Bare-OS JSON private envelope.
*
* Usage: ssh-keygen -t ed25519 -f PATH [-N pass] [-C comment]
* Encrypted private keys use bareOsKeySchema 2 (PBKDF2-SHA256 + ChaCha20-Poly1305), aligned with account crypto profile.
*/
import bareCrypto from 'bare-crypto'
import b4a from 'b4a'
import { PBKDF2_ITERATIONS, sealBytes } from './identity-account.js'
const { pbkdf2Sync, randomFillSync } = bareCrypto
/**
* @param {string} str
@@ -55,7 +59,8 @@ export async function runSshKeygenCli(ctx, argv) {
) {
ctx.console.log(
'Usage: ssh-keygen -t ed25519 -f KEYFILE [-N passphrase] [-C comment]\n' +
'Bare OS: writes KEYFILE (JSON private envelope) and KEYFILE.pub (ssh-ed25519 line).\n'
'Bare OS: writes KEYFILE (JSON private envelope) and KEYFILE.pub (ssh-ed25519 line).\n' +
'Passphrase: schema 2 sealed key (PBKDF2 + ChaCha20-Poly1305); empty -N for plaintext schema 1.\n'
)
return
}
@@ -87,14 +92,6 @@ export async function runSshKeygenCli(ctx, argv) {
ctx.exitCode = 1
return
}
if (pass !== '') {
ctx.console.error(
'ssh-keygen: encrypted private keys are not implemented; use -N "" only'
)
ctx.exitCode = 1
return
}
const vfs = ctx.vfs
const b4 = ctx.b4a
if (!vfs || typeof vfs.resolveLogical !== 'function' || !b4) {
@@ -111,19 +108,46 @@ export async function runSshKeygenCli(ctx, argv) {
const pubLine =
'ssh-ed25519 ' + b64(blob) + ' ' + (comment || 'bare-os-ed25519') + '\n'
const privJson =
JSON.stringify(
{
bareOsKeySchema: 1,
kty: 'ed25519',
sk: b64(secRaw),
pk: b64(pubRaw),
comment: comment || 'bare-os-ed25519',
atMs: Date.now()
},
null,
2
) + '\n'
/** @type {Record<string, unknown>} */
let privEnvelope
if (pass !== '') {
const salt = new Uint8Array(16)
randomFillSync(salt)
const dk = pbkdf2Sync(
utf8Bytes(pass),
salt,
PBKDF2_ITERATIONS,
32,
'sha256'
)
const inner = JSON.stringify({
sk: b64(secRaw),
pk: b64(pubRaw)
})
const sealed = sealBytes(dk, utf8Bytes(inner))
privEnvelope = {
bareOsKeySchema: 2,
kty: 'ed25519',
kdf: 'pbkdf2-sha256',
aead: 'chacha20-poly1305',
iterations: PBKDF2_ITERATIONS,
salt: b64(salt),
sealed: b64(sealed),
comment: comment || 'bare-os-ed25519',
atMs: Date.now()
}
} else {
privEnvelope = {
bareOsKeySchema: 1,
kty: 'ed25519',
sk: b64(secRaw),
pk: b64(pubRaw),
comment: comment || 'bare-os-ed25519',
atMs: Date.now()
}
}
const privJson = JSON.stringify(privEnvelope, null, 2) + '\n'
const absKey = vfs.resolveLogical(keyPath)
const absPub = vfs.resolveLogical(keyPath + '.pub')
+220
View File
@@ -0,0 +1,220 @@
/**
* Minimal WARC 1.0 tooling for Bare OS (no external WARC libraries).
* Supports listing record summaries and appending a single response record from a VFS file.
*/
import b4a from 'b4a'
const CRLF = '\r\n'
/**
* @param {Record<string, string>} fields
*/
function warcHeaderBlock(fields) {
const lines = ['WARC/1.0']
for (const [k, v] of Object.entries(fields)) {
const val = String(v).replace(/\r?\n/g, ' ')
lines.push(`${k}: ${val}`)
}
lines.push('')
lines.push('')
return b4a.from(lines.join(CRLF), 'utf8')
}
/**
* Parse WARC file buffer: yield { type, targetUri, contentLength } per record (best-effort).
* @param {Uint8Array} buf
*/
function* iterateWarcRecords(buf) {
let off = 0
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
while (off < u8.length) {
const start = off
const idx = indexOfHeaderEnd(u8, off)
if (idx < 0) break
const headerBytes = u8.subarray(off, idx)
off = idx + 4
const headerText = b4a.toString(headerBytes, 'utf8')
const cl = parseWarcHeaderNumber(headerText, 'Content-Length')
const warcType = parseWarcHeaderString(headerText, 'WARC-Type')
const targetUri = parseWarcHeaderString(headerText, 'WARC-Target-URI')
if (cl > 0 && off + cl <= u8.length) {
yield {
type: warcType || 'unknown',
targetUri: targetUri || '',
contentLength: cl,
headerOffset: start
}
off += cl
if (off < u8.length) {
const pad = (4 - (cl % 4 || 4)) % 4
off += pad
}
} else {
break
}
}
}
/**
* @param {Uint8Array} u8
* @param {number} from
*/
function indexOfHeaderEnd(u8, from) {
for (let i = from; i + 3 < u8.length; i++) {
if (
u8[i] === 0xd &&
u8[i + 1] === 0xa &&
u8[i + 2] === 0xd &&
u8[i + 3] === 0xa
) {
return i
}
}
return -1
}
/**
* @param {string} headerText
* @param {string} name
*/
function parseWarcHeaderNumber(headerText, name) {
const re = new RegExp('^' + name + ':\\s*(\\d+)\\s*$', 'mi')
const m = headerText.match(re)
return m ? Number.parseInt(m[1], 10) : 0
}
/**
* @param {string} headerText
* @param {string} name
*/
function parseWarcHeaderString(headerText, name) {
const re = new RegExp('^' + name + ':\\s*(.+)\\s*$', 'mi')
const m = headerText.match(re)
return m ? m[1].trim() : ''
}
/**
* @param {Record<string, unknown>} ctx
* @param {string[]} argv
*/
export async function runWarcCli(ctx, argv) {
const args = argv.slice(1)
if (
!args.length ||
args[0] === '-h' ||
args[0] === '--help' ||
args[0] === 'help'
) {
ctx.console.log(
'Usage:\n' +
' warc list FILE.warc — summarize WARC records\n' +
' warc write-response -o OUT -u URI -i INPUT — append one response record (VFS paths)\n'
)
return
}
const vfs = ctx.vfs
if (!vfs || typeof vfs.readFile !== 'function' || typeof vfs.writeFile !== 'function') {
ctx.console.error('warc: vfs unavailable')
ctx.exitCode = 1
return
}
if (args[0] === 'list' && args[1]) {
const p = String(args[1])
const abs = vfs.resolveLogical(p)
const buf = await vfs.readFile(abs)
if (!buf) {
ctx.console.error('warc: cannot read ' + p)
ctx.exitCode = 1
return
}
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
let n = 0
for (const rec of iterateWarcRecords(u8)) {
n++
ctx.console.log(
`${n}\t${rec.type}\t${rec.targetUri || '-'}\t${rec.contentLength}b`
)
}
if (n === 0) ctx.console.log('(no records parsed)')
return
}
if (args[0] === 'write-response') {
let outPath = ''
let uri = ''
let inPath = ''
for (let i = 1; i < args.length; i++) {
const a = args[i]
if (a === '-o') outPath = String(args[++i] || '')
else if (a === '-u') uri = String(args[++i] || '')
else if (a === '-i') inPath = String(args[++i] || '')
else {
ctx.console.error('warc: unknown argument ' + a)
ctx.exitCode = 1
return
}
}
if (!outPath || !uri || !inPath) {
ctx.console.error('warc: write-response requires -o OUT -u URI -i INPUT')
ctx.exitCode = 1
return
}
const absIn = vfs.resolveLogical(inPath)
const body = await vfs.readFile(absIn)
if (!body) {
ctx.console.error('warc: cannot read input ' + inPath)
ctx.exitCode = 1
return
}
const payload = body instanceof Uint8Array ? body : new Uint8Array(body)
const date = new Date().toISOString().replace(/\.\d{3}Z$/, 'Z')
const recordId = `<urn:uuid:${hexRandom(32)}>`
const fields = {
'WARC-Type': 'response',
'WARC-Target-URI': uri,
'WARC-Date': date,
'WARC-Record-ID': recordId,
'Content-Type': 'application/octet-stream',
'Content-Length': String(payload.length)
}
const head = warcHeaderBlock(fields)
const absOut = vfs.resolveLogical(outPath)
let existing = new Uint8Array(0)
try {
const prev = await vfs.readFile(absOut)
if (prev) existing = prev instanceof Uint8Array ? prev : new Uint8Array(prev)
} catch {
/* new file */
}
const pad = (4 - (payload.length % 4 || 4)) % 4
const tail = new Uint8Array(pad)
const merged = new Uint8Array(
existing.length + head.length + payload.length + tail.length
)
merged.set(existing, 0)
merged.set(head, existing.length)
merged.set(payload, existing.length + head.length)
merged.set(tail, existing.length + head.length + payload.length)
await vfs.writeFile(absOut, merged)
return
}
ctx.console.error('warc: unknown subcommand (try warc --help)')
ctx.exitCode = 1
}
function hexRandom(nibbles) {
const bytes = Math.ceil(nibbles / 2)
const u = new Uint8Array(bytes)
if (typeof globalThis.crypto?.getRandomValues === 'function') {
globalThis.crypto.getRandomValues(u)
} else {
for (let i = 0; i < bytes; i++) u[i] = (Math.random() * 256) | 0
}
let s = ''
for (let i = 0; i < bytes; i++) s += u[i].toString(16).padStart(2, '0')
return s.slice(0, nibbles)
}
@@ -3,12 +3,36 @@
"section": 1,
"title": "basenc",
"synopsis": [
"basenc [OPTION]... [OPERAND]..."
"basenc [--base16 | --base32 | --base64] [OPTION]... [OPERAND]..."
],
"description": "Encode or decode binary data. Default base is --base16 (hex). --base32 and --base64 follow RFC 4648. -d decodes text input to raw bytes on stdout. -w wraps encoded output (base32/base64). Defined in packages/bare-os-coreutils/src/basenc.js.",
"options": [
{
"flag": "--base16",
"meaning": "Hexadecimal (default when no base flag is given)."
},
{
"flag": "--base32",
"meaning": "RFC 4648 Base32."
},
{
"flag": "--base64",
"meaning": "RFC 4648 Base64."
},
{
"flag": "-d, --decode",
"meaning": "Decode from text to raw bytes."
},
{
"flag": "-w, --wrap COLS",
"meaning": "Wrap encoded lines (0 = no wrap)."
}
],
"description": "Bare OS implementation of basenc. Full behavior is defined in packages/bare-os-coreutils/src/basenc.js.",
"options": [],
"keywords": [
"basenc",
"base16",
"base32",
"base64",
"bare-os",
"coreutils"
]
+192 -19
View File
@@ -1,3 +1,5 @@
const B32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
function bareHexEncode(u8) {
let s = ''
for (let i = 0; i < u8.length; i++) {
@@ -17,16 +19,94 @@ function bareHexDecode(s) {
return out
}
function bareB32EncodeBytes(u8) {
let out = ''
let i = 0
let buf = 0
let bits = 0
for (; i < u8.length; i++) {
buf = (buf << 8) | u8[i]
bits += 8
while (bits >= 5) {
bits -= 5
out += B32[(buf >> bits) & 31]
}
}
if (bits > 0) out += B32[(buf << (5 - bits)) & 31]
while (out.length % 8 !== 0) out += '='
return out
}
function bareB32DecodeToU8(s) {
const t = String(s).replace(/\s+/g, '').replace(/=+$/, '')
let buf = 0
let bits = 0
const bytes = []
for (let i = 0; i < t.length; i++) {
const c = t[i]
const v = B32.indexOf(c)
if (v < 0) throw new Error('invalid base32 character')
buf = (buf << 5) | v
bits += 5
if (bits >= 8) {
bits -= 8
bytes.push((buf >> bits) & 255)
}
}
return new Uint8Array(bytes)
}
function bareB64EncodeBytes(u8) {
const B =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
let out = ''
let i = 0
for (; i + 2 < u8.length; i += 3) {
const n = (u8[i] << 16) | (u8[i + 1] << 8) | u8[i + 2]
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + B[(n >> 6) & 63] + B[n & 63]
}
const rest = u8.length - i
if (rest === 1) {
const n = u8[i] << 16
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + '=='
} else if (rest === 2) {
const n = (u8[i] << 16) | (u8[i + 1] << 8)
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + B[(n >> 6) & 63] + '='
}
return out
}
function bareB64DecodeToU8(s) {
const t = String(s).replace(/\s+/g, '')
if (typeof globalThis.Buffer !== 'undefined') {
return new Uint8Array(globalThis.Buffer.from(t, 'base64'))
}
if (typeof globalThis.atob === 'function') {
const bin = globalThis.atob(t)
const out = new Uint8Array(bin.length)
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i) & 255
return out
}
throw new Error('base64 decode requires Buffer or atob')
}
async function run(ctx, argv) {
let decode = false
let base16 = false
let base32 = false
let base64 = false
let wrap = 0
const paths = []
for (let i = 1; i < argv.length; i++) {
const a = argv[i]
if (a === '-h' || a === '--help') {
ctx.console.log(
'usage: basenc --base16 [-d] [FILE]\n' +
'Encode or decode hex (Base16). Other bases are not implemented.'
'usage: basenc [--base16 | --base32 | --base64] [-d] [-w COLS] [FILE]\n' +
' --base16 hex (default when no base flag)\n' +
' --base32 RFC 4648 Base32\n' +
' --base64 RFC 4648 Base64\n' +
' -d decode from text to raw bytes (stdout)\n' +
' -w COLS wrap encoded output (base64/base32 only; 0 = no wrap)'
)
ctx.exitCode = 0
return
@@ -39,6 +119,19 @@ async function run(ctx, argv) {
base16 = true
continue
}
if (a === '--base32') {
base32 = true
continue
}
if (a === '--base64') {
base64 = true
continue
}
if ((a === '-w' || a === '--wrap') && argv[i + 1]) {
wrap = Number.parseInt(argv[++i], 10)
if (!Number.isFinite(wrap) || wrap < 0) wrap = 0
continue
}
if (a.startsWith('-')) {
ctx.console.error('basenc: unsupported option ' + a)
ctx.exitCode = 1
@@ -46,11 +139,15 @@ async function run(ctx, argv) {
}
paths.push(a)
}
if (!base16) {
ctx.console.error('basenc: requires --base16')
const modeCount = (base16 ? 1 : 0) + (base32 ? 1 : 0) + (base64 ? 1 : 0)
if (modeCount > 1) {
ctx.console.error('basenc: specify at most one of --base16, --base32, --base64')
ctx.exitCode = 1
return
}
if (modeCount === 0) base16 = true
const b4 = ctx.b4a
let buf
if (!paths.length || paths[0] === '-') {
@@ -64,23 +161,99 @@ async function run(ctx, argv) {
}
buf = b instanceof Uint8Array ? b : new Uint8Array(b)
}
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareHexDecode(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
if (base16) {
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareHexDecode(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
ctx.console.log(bareHexEncode(buf))
return
}
ctx.console.log(bareHexEncode(buf))
if (base32) {
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareB32DecodeToU8(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
let enc = bareB32EncodeBytes(buf)
if (wrap > 0) {
const lines = []
for (let i = 0; i < enc.length; i += wrap) {
lines.push(enc.slice(i, i + wrap))
}
enc = lines.join('\n')
}
ctx.console.log(enc)
return
}
if (base64) {
if (decode) {
const text = new TextDecoder().decode(buf)
let raw
try {
raw = bareB64DecodeToU8(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
let enc
if (typeof globalThis.btoa === 'function') {
let s = ''
const step = 0x8000
for (let i = 0; i < buf.length; i += step) {
const chunk = buf.subarray(i, i + step)
s += String.fromCharCode.apply(null, chunk)
}
enc = globalThis.btoa(s)
} else {
enc = bareB64EncodeBytes(buf)
}
if (wrap > 0) {
const lines = []
for (let i = 0; i < enc.length; i += wrap) {
lines.push(enc.slice(i, i + wrap))
}
enc = lines.join('\n')
}
ctx.console.log(enc)
}
}
+17 -1
View File
@@ -1,7 +1,9 @@
async function run(ctx, argv) {
for (let i = 1; i < argv.length; i++) {
if (argv[i] === '-h' || argv[i] === '--help') {
ctx.console.log('usage: hostid\nPrint a numeric host identifier (session-derived stub).')
ctx.console.log(
'usage: hostid\nPrint an 8-digit hex host identifier: HOSTID env, else identity public key hash, else session-derived.'
)
return
}
if (argv[i].startsWith('-')) {
@@ -15,6 +17,20 @@ async function run(ctx, argv) {
ctx.console.log(e.HOSTID.toLowerCase())
return
}
const id = ctx.identity
const pk =
id &&
id.state === 'unlocked' &&
id.publicKey instanceof Uint8Array &&
id.publicKey.length
? id.publicKey
: null
if (pk) {
let h = 0
for (let i = 0; i < pk.length; i++) h = (Math.imul(31, h) + pk[i]) >>> 0
ctx.console.log(h.toString(16).padStart(8, '0'))
return
}
const seed = e.BARE_OS_SESSION_ID || e.HOSTNAME || 'bare-os'
let h = 0
for (let i = 0; i < seed.length; i++)
+3 -1
View File
@@ -1,7 +1,9 @@
async function run(ctx, argv) {
for (let i = 1; i < argv.length; i++) {
if (argv[i] === '-h' || argv[i] === '--help') {
ctx.console.log('usage: users\nPrint login names (single-session stub).')
ctx.console.log(
'usage: users\nPrint login names for the active Bare OS session (USER / LOGNAME from VFS env).'
)
return
}
if (argv[i].startsWith('-')) {
+192 -19
View File
@@ -87,6 +87,8 @@ function bareOsEmitRaw(ctx, chunk) {
return false
}
const B32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
function bareHexEncode(u8) {
let s = ''
for (let i = 0; i < u8.length; i++) {
@@ -106,16 +108,94 @@ function bareHexDecode(s) {
return out
}
function bareB32EncodeBytes(u8) {
let out = ''
let i = 0
let buf = 0
let bits = 0
for (; i < u8.length; i++) {
buf = (buf << 8) | u8[i]
bits += 8
while (bits >= 5) {
bits -= 5
out += B32[(buf >> bits) & 31]
}
}
if (bits > 0) out += B32[(buf << (5 - bits)) & 31]
while (out.length % 8 !== 0) out += '='
return out
}
function bareB32DecodeToU8(s) {
const t = String(s).replace(/\s+/g, '').replace(/=+$/, '')
let buf = 0
let bits = 0
const bytes = []
for (let i = 0; i < t.length; i++) {
const c = t[i]
const v = B32.indexOf(c)
if (v < 0) throw new Error('invalid base32 character')
buf = (buf << 5) | v
bits += 5
if (bits >= 8) {
bits -= 8
bytes.push((buf >> bits) & 255)
}
}
return new Uint8Array(bytes)
}
function bareB64EncodeBytes(u8) {
const B =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
let out = ''
let i = 0
for (; i + 2 < u8.length; i += 3) {
const n = (u8[i] << 16) | (u8[i + 1] << 8) | u8[i + 2]
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + B[(n >> 6) & 63] + B[n & 63]
}
const rest = u8.length - i
if (rest === 1) {
const n = u8[i] << 16
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + '=='
} else if (rest === 2) {
const n = (u8[i] << 16) | (u8[i + 1] << 8)
out += B[(n >> 18) & 63] + B[(n >> 12) & 63] + B[(n >> 6) & 63] + '='
}
return out
}
function bareB64DecodeToU8(s) {
const t = String(s).replace(/\s+/g, '')
if (typeof globalThis.Buffer !== 'undefined') {
return new Uint8Array(globalThis.Buffer.from(t, 'base64'))
}
if (typeof globalThis.atob === 'function') {
const bin = globalThis.atob(t)
const out = new Uint8Array(bin.length)
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i) & 255
return out
}
throw new Error('base64 decode requires Buffer or atob')
}
async function run(ctx, argv) {
let decode = false
let base16 = false
let base32 = false
let base64 = false
let wrap = 0
const paths = []
for (let i = 1; i < argv.length; i++) {
const a = argv[i]
if (a === '-h' || a === '--help') {
ctx.console.log(
'usage: basenc --base16 [-d] [FILE]\n' +
'Encode or decode hex (Base16). Other bases are not implemented.'
'usage: basenc [--base16 | --base32 | --base64] [-d] [-w COLS] [FILE]\n' +
' --base16 hex (default when no base flag)\n' +
' --base32 RFC 4648 Base32\n' +
' --base64 RFC 4648 Base64\n' +
' -d decode from text to raw bytes (stdout)\n' +
' -w COLS wrap encoded output (base64/base32 only; 0 = no wrap)'
)
ctx.exitCode = 0
return
@@ -128,6 +208,19 @@ async function run(ctx, argv) {
base16 = true
continue
}
if (a === '--base32') {
base32 = true
continue
}
if (a === '--base64') {
base64 = true
continue
}
if ((a === '-w' || a === '--wrap') && argv[i + 1]) {
wrap = Number.parseInt(argv[++i], 10)
if (!Number.isFinite(wrap) || wrap < 0) wrap = 0
continue
}
if (a.startsWith('-')) {
ctx.console.error('basenc: unsupported option ' + a)
ctx.exitCode = 1
@@ -135,11 +228,15 @@ async function run(ctx, argv) {
}
paths.push(a)
}
if (!base16) {
ctx.console.error('basenc: requires --base16')
const modeCount = (base16 ? 1 : 0) + (base32 ? 1 : 0) + (base64 ? 1 : 0)
if (modeCount > 1) {
ctx.console.error('basenc: specify at most one of --base16, --base32, --base64')
ctx.exitCode = 1
return
}
if (modeCount === 0) base16 = true
const b4 = ctx.b4a
let buf
if (!paths.length || paths[0] === '-') {
@@ -153,23 +250,99 @@ async function run(ctx, argv) {
}
buf = b instanceof Uint8Array ? b : new Uint8Array(b)
}
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareHexDecode(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
if (base16) {
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareHexDecode(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
ctx.console.log(bareHexEncode(buf))
return
}
ctx.console.log(bareHexEncode(buf))
if (base32) {
if (decode) {
const text = b4.toString(buf)
let raw
try {
raw = bareB32DecodeToU8(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
let enc = bareB32EncodeBytes(buf)
if (wrap > 0) {
const lines = []
for (let i = 0; i < enc.length; i += wrap) {
lines.push(enc.slice(i, i + wrap))
}
enc = lines.join('\n')
}
ctx.console.log(enc)
return
}
if (base64) {
if (decode) {
const text = new TextDecoder().decode(buf)
let raw
try {
raw = bareB64DecodeToU8(text)
} catch (e) {
ctx.console.error('basenc: ' + (e.message || e))
ctx.exitCode = 1
return
}
if (!bareOsEmitRaw(ctx, raw)) {
ctx.console.error(
'basenc: decode output requires process.stdout.write or ctx.bareOsBinWrite'
)
ctx.exitCode = 1
}
return
}
let enc
if (typeof globalThis.btoa === 'function') {
let s = ''
const step = 0x8000
for (let i = 0; i < buf.length; i += step) {
const chunk = buf.subarray(i, i + step)
s += String.fromCharCode.apply(null, chunk)
}
enc = globalThis.btoa(s)
} else {
enc = bareB64EncodeBytes(buf)
}
if (wrap > 0) {
const lines = []
for (let i = 0; i < enc.length; i += wrap) {
lines.push(enc.slice(i, i + wrap))
}
enc = lines.join('\n')
}
ctx.console.log(enc)
}
}
+17 -1
View File
@@ -90,7 +90,9 @@ function bareOsEmitRaw(ctx, chunk) {
async function run(ctx, argv) {
for (let i = 1; i < argv.length; i++) {
if (argv[i] === '-h' || argv[i] === '--help') {
ctx.console.log('usage: hostid\nPrint a numeric host identifier (session-derived stub).')
ctx.console.log(
'usage: hostid\nPrint an 8-digit hex host identifier: HOSTID env, else identity public key hash, else session-derived.'
)
return
}
if (argv[i].startsWith('-')) {
@@ -104,6 +106,20 @@ async function run(ctx, argv) {
ctx.console.log(e.HOSTID.toLowerCase())
return
}
const id = ctx.identity
const pk =
id &&
id.state === 'unlocked' &&
id.publicKey instanceof Uint8Array &&
id.publicKey.length
? id.publicKey
: null
if (pk) {
let h = 0
for (let i = 0; i < pk.length; i++) h = (Math.imul(31, h) + pk[i]) >>> 0
ctx.console.log(h.toString(16).padStart(8, '0'))
return
}
const seed = e.BARE_OS_SESSION_ID || e.HOSTNAME || 'bare-os'
let h = 0
for (let i = 0; i < seed.length; i++)
@@ -1,8 +1,11 @@
/* BARE_OS_BIN_API 1.0.0 — stub; booter delegates to systemctl-cli (kernel-runner). */
/** Booter delegates journalctl to systemctl-cli.js (kernel-runner). */
/* BARE_OS_BIN_API 1.0.0 — delegates to booter systemctl-cli when ctx exposes bareOsRunSystemctlCli. */
async function run(ctx, argv) {
if (typeof ctx.bareOsRunSystemctlCli === 'function') {
await ctx.bareOsRunSystemctlCli(argv)
return
}
ctx.console.error(
'journalctl: not executed in host booter (delegation missing)'
'journalctl: ctx.bareOsRunSystemctlCli missing — run under host booter / upgrade ctx API'
)
ctx.exitCode = 1
}
+6 -3
View File
@@ -1,8 +1,11 @@
/* BARE_OS_BIN_API 1.0.0 — stub; booter delegates to systemctl-cli (kernel-runner). */
/** Booter delegates systemctl to systemctl-cli.js (kernel-runner). */
/* BARE_OS_BIN_API 1.0.0 — delegates to booter systemctl-cli when ctx exposes bareOsRunSystemctlCli. */
async function run(ctx, argv) {
if (typeof ctx.bareOsRunSystemctlCli === 'function') {
await ctx.bareOsRunSystemctlCli(argv)
return
}
ctx.console.error(
'systemctl: not executed in host booter (delegation missing)'
'systemctl: ctx.bareOsRunSystemctlCli missing — run under host booter / upgrade ctx API'
)
ctx.exitCode = 1
}
+3 -1
View File
@@ -90,7 +90,9 @@ function bareOsEmitRaw(ctx, chunk) {
async function run(ctx, argv) {
for (let i = 1; i < argv.length; i++) {
if (argv[i] === '-h' || argv[i] === '--help') {
ctx.console.log('usage: users\nPrint login names (single-session stub).')
ctx.console.log(
'usage: users\nPrint login names for the active Bare OS session (USER / LOGNAME from VFS env).'
)
return
}
if (argv[i].startsWith('-')) {
@@ -2,9 +2,9 @@
"version": 1,
"bundles": [
{
"path": "/lib/bare/bundles/safetyCatch.js",
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
"keys": [
"safetyCatch"
"hypercoreIdEncoding"
]
},
{
@@ -14,9 +14,9 @@
]
},
{
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
"path": "/lib/bare/bundles/safetyCatch.js",
"keys": [
"hypercoreIdEncoding"
"safetyCatch"
]
},
{
@@ -25,6 +25,12 @@
"compactEncoding"
]
},
{
"path": "/lib/bare/bundles/protomux.js",
"keys": [
"protomux"
]
},
{
"path": "/lib/bare/bundles/bareUrl.js",
"keys": [
@@ -32,9 +38,9 @@
]
},
{
"path": "/lib/bare/bundles/protomux.js",
"path": "/lib/bare/bundles/bareEvents.js",
"keys": [
"protomux"
"bareEvents"
]
},
{
@@ -49,24 +55,12 @@
"barePath"
]
},
{
"path": "/lib/bare/bundles/bareEvents.js",
"keys": [
"bareEvents"
]
},
{
"path": "/lib/bare/bundles/bareAbort.js",
"keys": [
"bareAbort"
]
},
{
"path": "/lib/bare/bundles/bareAbortController.js",
"keys": [
"bareAbortController"
]
},
{
"path": "/lib/bare/bundles/bareAnsiEscapes.js",
"keys": [
@@ -74,9 +68,9 @@
]
},
{
"path": "/lib/bare/bundles/bareReadline.js",
"path": "/lib/bare/bundles/bareAbortController.js",
"keys": [
"bareReadline"
"bareAbortController"
]
},
{
@@ -92,9 +86,9 @@
]
},
{
"path": "/lib/bare/bundles/bareApk.js",
"path": "/lib/bare/bundles/bareReadline.js",
"keys": [
"bareApk"
"bareReadline"
]
},
{
@@ -104,9 +98,9 @@
]
},
{
"path": "/lib/bare/bundles/fetch.js",
"path": "/lib/bare/bundles/bareAppKit.js",
"keys": [
"fetch"
"bareAppKit"
]
},
{
@@ -122,9 +116,15 @@
]
},
{
"path": "/lib/bare/bundles/bareAppKit.js",
"path": "/lib/bare/bundles/bareApk.js",
"keys": [
"bareAppKit"
"bareApk"
]
},
{
"path": "/lib/bare/bundles/fetch.js",
"keys": [
"fetch"
]
},
{
@@ -140,9 +140,9 @@
]
},
{
"path": "/lib/bare/bundles/bareBluetoothApple.js",
"path": "/lib/bare/bundles/bareBundle.js",
"keys": [
"bareBluetoothApple"
"bareBundle"
]
},
{
@@ -152,9 +152,9 @@
]
},
{
"path": "/lib/bare/bundles/bareBundle.js",
"path": "/lib/bare/bundles/bareBluetoothApple.js",
"keys": [
"bareBundle"
"bareBluetoothApple"
]
},
{
@@ -169,12 +169,6 @@
"bareBoot"
]
},
{
"path": "/lib/bare/bundles/bareDebugLog.js",
"keys": [
"bareDebugLog"
]
},
{
"path": "/lib/bare/bundles/bareConsole.js",
"keys": [
@@ -199,6 +193,12 @@
"bareDelta"
]
},
{
"path": "/lib/bare/bundles/bareDebugLog.js",
"keys": [
"bareDebugLog"
]
},
{
"path": "/lib/bare/bundles/bareDaemon.js",
"keys": [
@@ -241,12 +241,6 @@
"bareDgram"
]
},
{
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
"keys": [
"bareFfmpegEncodings"
]
},
{
"path": "/lib/bare/bundles/bareFfmpeg.js",
"keys": [
@@ -254,15 +248,9 @@
]
},
{
"path": "/lib/bare/bundles/bareGif.js",
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
"keys": [
"bareGif"
]
},
{
"path": "/lib/bare/bundles/bareFormat.js",
"keys": [
"bareFormat"
"bareFfmpegEncodings"
]
},
{
@@ -271,6 +259,12 @@
"bareFormData"
]
},
{
"path": "/lib/bare/bundles/bareFormat.js",
"keys": [
"bareFormat"
]
},
{
"path": "/lib/bare/bundles/bareFileLogger.js",
"keys": [
@@ -278,21 +272,9 @@
]
},
{
"path": "/lib/bare/bundles/bareGtk.js",
"path": "/lib/bare/bundles/bareGif.js",
"keys": [
"bareGtk"
]
},
{
"path": "/lib/bare/bundles/bareFs.js",
"keys": [
"bareFs"
]
},
{
"path": "/lib/bare/bundles/bareHeif.js",
"keys": [
"bareHeif"
"bareGif"
]
},
{
@@ -301,12 +283,30 @@
"bareHrtime"
]
},
{
"path": "/lib/bare/bundles/bareHeif.js",
"keys": [
"bareHeif"
]
},
{
"path": "/lib/bare/bundles/bareGtk.js",
"keys": [
"bareGtk"
]
},
{
"path": "/lib/bare/bundles/bareHttpParser.js",
"keys": [
"bareHttpParser"
]
},
{
"path": "/lib/bare/bundles/bareFs.js",
"keys": [
"bareFs"
]
},
{
"path": "/lib/bare/bundles/bareIco.js",
"keys": [
@@ -320,15 +320,9 @@
]
},
{
"path": "/lib/bare/bundles/bareInspect.js",
"path": "/lib/bare/bundles/bareHttps.js",
"keys": [
"bareInspect"
]
},
{
"path": "/lib/bare/bundles/bareIntl.js",
"keys": [
"bareIntl"
"bareHttps"
]
},
{
@@ -337,6 +331,12 @@
"bareHttp1"
]
},
{
"path": "/lib/bare/bundles/bareInspect.js",
"keys": [
"bareInspect"
]
},
{
"path": "/lib/bare/bundles/bareJpeg.js",
"keys": [
@@ -344,15 +344,9 @@
]
},
{
"path": "/lib/bare/bundles/bareHttps.js",
"path": "/lib/bare/bundles/bareIntl.js",
"keys": [
"bareHttps"
]
},
{
"path": "/lib/bare/bundles/bareInspector.js",
"keys": [
"bareInspector"
"bareIntl"
]
},
{
@@ -361,18 +355,24 @@
"bareIpc"
]
},
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{
"path": "/lib/bare/bundles/bareLief.js",
"keys": [
"bareLief"
]
},
{
"path": "/lib/bare/bundles/bareInspector.js",
"keys": [
"bareInspector"
]
},
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{
"path": "/lib/bare/bundles/bareLink.js",
"keys": [
@@ -385,18 +385,18 @@
"bareMake"
]
},
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{
"path": "/lib/bare/bundles/bareModuleResolve.js",
"keys": [
"bareModuleResolve"
]
},
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{
"path": "/lib/bare/bundles/bareModule.js",
"keys": [
@@ -451,12 +451,6 @@
"bareMedia"
]
},
{
"path": "/lib/bare/bundles/barePack.js",
"keys": [
"barePack"
]
},
{
"path": "/lib/bare/bundles/barePerformance.js",
"keys": [
@@ -470,9 +464,9 @@
]
},
{
"path": "/lib/bare/bundles/barePipe.js",
"path": "/lib/bare/bundles/barePack.js",
"keys": [
"barePipe"
"barePack"
]
},
{
@@ -482,15 +476,15 @@
]
},
{
"path": "/lib/bare/bundles/bareNodeRuntime.js",
"path": "/lib/bare/bundles/barePipe.js",
"keys": [
"bareNodeRuntime"
"barePipe"
]
},
{
"path": "/lib/bare/bundles/barePrebuild.js",
"path": "/lib/bare/bundles/bareNodeRuntime.js",
"keys": [
"barePrebuild"
"bareNodeRuntime"
]
},
{
@@ -499,18 +493,24 @@
"barePunycode"
]
},
{
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareDev"
]
},
{
"path": "/lib/bare/bundles/bareQuerystring.js",
"keys": [
"bareQuerystring"
]
},
{
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
"keys": [
"bareQueueMicrotask"
]
},
{
"path": "/lib/bare/bundles/barePrebuild.js",
"keys": [
"barePrebuild"
]
},
{
"path": "/lib/bare/bundles/bareRealm.js",
"keys": [
@@ -518,9 +518,9 @@
]
},
{
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareQueueMicrotask"
"bareDev"
]
},
{
@@ -553,12 +553,6 @@
"bareSemver"
]
},
{
"path": "/lib/bare/bundles/bareRpc.js",
"keys": [
"bareRpc"
]
},
{
"path": "/lib/bare/bundles/bareRepl.js",
"keys": [
@@ -566,9 +560,9 @@
]
},
{
"path": "/lib/bare/bundles/bareRun.js",
"path": "/lib/bare/bundles/bareRpc.js",
"keys": [
"bareRun"
"bareRpc"
]
},
{
@@ -583,12 +577,24 @@
"bareSidecar"
]
},
{
"path": "/lib/bare/bundles/bareRun.js",
"keys": [
"bareRun"
]
},
{
"path": "/lib/bare/bundles/bareStringDecoder.js",
"keys": [
"bareStringDecoder"
]
},
{
"path": "/lib/bare/bundles/bareStdio.js",
"keys": [
"bareStdio"
]
},
{
"path": "/lib/bare/bundles/bareStorage.js",
"keys": [
@@ -602,9 +608,9 @@
]
},
{
"path": "/lib/bare/bundles/bareStdio.js",
"path": "/lib/bare/bundles/bareStructuredClone.js",
"keys": [
"bareStdio"
"bareStructuredClone"
]
},
{
@@ -613,36 +619,12 @@
"bareSvg"
]
},
{
"path": "/lib/bare/bundles/bareStructuredClone.js",
"keys": [
"bareStructuredClone"
]
},
{
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareSystemLogger"
]
},
{
"path": "/lib/bare/bundles/bareSubprocess.js",
"keys": [
"bareSubprocess"
]
},
{
"path": "/lib/bare/bundles/bareTcp.js",
"keys": [
"bareTcp"
]
},
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{
"path": "/lib/bare/bundles/bareTiff.js",
"keys": [
@@ -650,9 +632,15 @@
]
},
{
"path": "/lib/bare/bundles/bareThread.js",
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareThread"
"bareSystemLogger"
]
},
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{
@@ -662,9 +650,15 @@
]
},
{
"path": "/lib/bare/bundles/bareType.js",
"path": "/lib/bare/bundles/bareTcp.js",
"keys": [
"bareType"
"bareTcp"
]
},
{
"path": "/lib/bare/bundles/bareThread.js",
"keys": [
"bareThread"
]
},
{
@@ -674,9 +668,9 @@
]
},
{
"path": "/lib/bare/bundles/bareUiKit.js",
"path": "/lib/bare/bundles/bareType.js",
"keys": [
"bareUiKit"
"bareType"
]
},
{
@@ -685,6 +679,12 @@
"bareTls"
]
},
{
"path": "/lib/bare/bundles/bareUiKit.js",
"keys": [
"bareUiKit"
]
},
{
"path": "/lib/bare/bundles/bareTty.js",
"keys": [
@@ -697,12 +697,6 @@
"bareUnpack"
]
},
{
"path": "/lib/bare/bundles/bareVm.js",
"keys": [
"bareVm"
]
},
{
"path": "/lib/bare/bundles/bareV8.js",
"keys": [
@@ -715,6 +709,18 @@
"bareWalkHandles"
]
},
{
"path": "/lib/bare/bundles/bareVm.js",
"keys": [
"bareVm"
]
},
{
"path": "/lib/bare/bundles/bareWebKit.js",
"keys": [
"bareWebKit"
]
},
{
"path": "/lib/bare/bundles/bareUnionBundle.js",
"keys": [
@@ -727,30 +733,12 @@
"bareWebp"
]
},
{
"path": "/lib/bare/bundles/bareWebKit.js",
"keys": [
"bareWebKit"
]
},
{
"path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [
"bareWebKitGtk"
]
},
{
"path": "/lib/bare/bundles/bareUtils.js",
"keys": [
"bareUtils"
]
},
{
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
"keys": [
"bareV8ToIstanbul"
]
},
{
"path": "/lib/bare/bundles/bareWhich.js",
"keys": [
@@ -758,9 +746,9 @@
]
},
{
"path": "/lib/bare/bundles/bareXdiff.js",
"path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [
"bareXdiff"
"bareWebKitGtk"
]
},
{
@@ -770,15 +758,27 @@
]
},
{
"path": "/lib/bare/bundles/bareZlib.js",
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
"keys": [
"bareZlib"
"bareV8ToIstanbul"
]
},
{
"path": "/lib/bare/bundles/bareWs.js",
"path": "/lib/bare/bundles/bareXdiff.js",
"keys": [
"bareWs"
"bareXdiff"
]
},
{
"path": "/lib/bare/bundles/bareZmq.js",
"keys": [
"bareZmq"
]
},
{
"path": "/lib/bare/bundles/bareZlib.js",
"keys": [
"bareZlib"
]
},
{
@@ -788,9 +788,9 @@
]
},
{
"path": "/lib/bare/bundles/bareZmq.js",
"path": "/lib/bare/bundles/bareWs.js",
"keys": [
"bareZmq"
"bareWs"
]
}
],
@@ -1,6 +1,6 @@
{
"schema": 1,
"atMs": 1775339424020,
"atMs": 1775340363610,
"commands": [
"arch",
"awk",
File diff suppressed because one or more lines are too long
+6
View File
@@ -77,6 +77,12 @@ Appends one NDJSON trend row (`schema: 1`) to **`BARE_OS_BENCHMARK_TREND_NDJSON`
Ensures [docs/reference/naming-alias-matrix.md](../docs/reference/naming-alias-matrix.md) lists canonical **`ctx`** boot-hook names and boot-policy key aliases. Root **`pretest`**.
## `verify-booter-boot-steps-alignment.mjs`
**Usage:** `node scripts/verify-booter-boot-steps-alignment.mjs`
Ensures every **`emitBooterBootPhase('…')`** in **`packages/bare-os-booter/index.js`** matches **`BARE_OS_BOOTER_BOOT_STEPS`** in **`packages/bare-os-booter/lib/bare-os-boot-phases.js`** (no drift). Root **`pretest`**.
## `verify-runtime-no-incomplete-markers.mjs`
**Usage:** `node scripts/verify-runtime-no-incomplete-markers.mjs`
@@ -0,0 +1,66 @@
#!/usr/bin/env node
/**
* CI: every emitBooterBootPhase('…') in the booter matches BARE_OS_BOOTER_BOOT_STEPS.
*/
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const indexPath = path.join(root, 'packages', 'bare-os-booter', 'index.js')
const phasesPath = path.join(
root,
'packages',
'bare-os-booter',
'lib',
'bare-os-boot-phases.js'
)
function extractArray(src) {
const m = src.match(
/export const BARE_OS_BOOTER_BOOT_STEPS = Object\.freeze\(\[([\s\S]*?)\]\)/
)
if (!m) return null
const inner = m[1]
const steps = []
for (const q of inner.matchAll(/'([^']+)'/g)) steps.push(q[1])
return steps
}
function main() {
const phaseSrc = fs.readFileSync(phasesPath, 'utf8')
const declared = extractArray(phaseSrc)
if (!declared || !declared.length) {
console.error('verify-booter-boot-steps-alignment: could not parse boot phases')
process.exit(1)
}
const idx = fs.readFileSync(indexPath, 'utf8')
const used = new Set()
for (const m of idx.matchAll(/emitBooterBootPhase\(\s*'([^']+)'\s*\)/g)) {
used.add(m[1])
}
const declSet = new Set(declared)
for (const u of used) {
if (!declSet.has(u)) {
console.error(
'verify-booter-boot-steps-alignment: index.js uses unknown step:',
u,
'— add to bare-os-boot-phases.js or fix typo'
)
process.exit(1)
}
}
for (const d of declared) {
if (!used.has(d)) {
console.error(
'verify-booter-boot-steps-alignment: declared step unused in index.js:',
d
)
process.exit(1)
}
}
console.log('verify-booter-boot-steps-alignment: OK')
}
main()
+1
View File
@@ -35,6 +35,7 @@ const needles = [
'bareOsRunOpensslCli',
'bareOsRunSshKeygenCli',
'bareOsRunTarCli',
'bareOsRunSystemctlCli',
'bareOsReleaseKeyHandle',
'bareOsAuditLogAppend',
'bareOsAclEvaluate',