feat: POSIX/P2P roadmap — proc surfaces, syscalls, boot perf, docs, CI

- Align posix-conformance-matrix bareOsSyscallOps with getconf BARE_OS_SYSCALL_OPS
- Add verify-boot-policy-extension-signer-pins.mjs to pretest; document in scripts/README
- Document extensionSignerPinsV2–V5 env wiring in OTA_AND_BUNDLES; vault multisig sketch
- Note telemetry NDJSON redaction limits in environment appendix
- Expand booter CHANGELOG 1.40.0 (boot-perf, shell POSIX mode, subprocess errors, etc.)
- Holepunch sync README: NDJSON summary path

Seeder/kernel parity and pretest already green for bundled changes.
This commit is contained in:
Raven Scott
2026-04-05 00:02:23 -04:00
parent 16ac71815f
commit 1faf9715b7
67 changed files with 2645 additions and 577 deletions
+4 -2
View File
@@ -5,7 +5,7 @@ Authoritative **version alignment** with protocol and telemetry schema numbers l
## Maintenance
- **Host filesystem**: first-party booter and seeder sources use **`import … from '#host-fs'`** / **`#host-path`** (and seeder **`#host-fs-promises`**) so Bare resolves **`bare-fs`** / **`bare-path`** and Node resolves the built-in **`fs`** / **`path`** modules via the default **`imports`** condition. **`bare-fs`** is a direct **`dependencies`** entry of **`bare-os-booter`**. CI: **`scripts/verify-pear-no-static-node-import.mjs`** rejects bare **`fs`** / **`path`** specifiers.
- **POSIX / proc**: **`/proc/bare_os/syscalls.json`** schema **5** (socket-family probes, **`posixXsh`** / **`fdModel`** extensions; JSON text **cached** until **`vfs.bareOsClearWarmReadCaches`**); **`/proc/bare_os/process_table.json`** schema **5** (**`parentName`**); **`/proc/bare_os/protomux.json`** wire text schema **2**; **`/dev/shm`** in-memory named segments. Protocol export **`BARE_OS_POSIX_PROFILE_*`**.
- **POSIX / proc**: **`/proc/bare_os/syscalls.json`** schema **5** (socket-family probes, **`posixXsh`** / **`fdModel`** / **`errnoAlignment`**; JSON text **cached** until **`vfs.bareOsClearWarmReadCaches`**); **`/proc/bare_os/process_table.json`** schema **6** (**`jobControlSemantics`** + **`parentName`**); **`/proc/bare_os/protomux.json`** wire text schema **2**; **`/dev/shm`** in-memory named segments. Protocol export **`BARE_OS_POSIX_PROFILE_*`**.
- **Vendored bundles**: post-esbuild **`scripts/sanitize-bare-bundles.mjs`** (from **`bare-os-bare-libs/build.mjs`**) strips CI-forbidden markers and replaces **`node:`** requires in **`bareDev.js`** with **`bare-*`** modules.
- **Boot hooks (naming)**: canonical **`bareOsRegisterBootStepHook`**, **`bareOsInvokeBootStepHooks`**, **`bareOsEmitBareBootStepHint`**; legacy **`*BootPhase*`** methods remain thin wrappers (**no `bareOsCtxApiVersion` bump**). See [docs/reference/naming-alias-matrix.md](../../docs/reference/naming-alias-matrix.md).
- **Pear / Bare**: [`lib/kernel-runner.js`](lib/kernel-runner.js) must not **static**-import **`node:module`** (Bares resolver cannot load **`node:`** builtins from a **`pear://`** bundle). Optional **`BARE_OS_BIN_WORKER_OFFLOAD`** now obtains **`createRequire`** via **dynamic** **`import('bare-module')`** when running outside Node.
@@ -15,7 +15,9 @@ Authoritative **version alignment** with protocol and telemetry schema numbers l
| Version | Booter (workspace) | Notes |
| ------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 1.38.0 | 0.1.0 | **`/proc/bare_os/syscalls.json`** schema **5** + **cached** proc text (cleared with warm read cache); socket syscall **probes** (**`ENOSYS`**); **`/dev/shm`** segments; **`net_summary`** **`udxTuning`** / **`hyperswarmTuning`** env passthrough; **`bareOsCorestoreSnapshotHint`** → **`operator.corestore_snapshot_hint`** counter; **`bareOsPathconf`** **`_PC_NAME_MAX`** **128** under **`/dev/shm`**. |
| 1.40.0 | 0.1.0 | **`vfs.bareOsEvictLibBareBundlesFromManifest`** + **`ctx.bareOsInvalidateWarmReadCachesFromBareManifestJson`** — manifest-aware **`/lib/bare`** warm-cache eviction; **`bareOsVfsBatchWrite`** uses selective eviction for manifest-only puts. **`/proc/bare_os/replication`** **`liveHyperdrive`** sketch + **`metrics_live.replicationLive`** (**`stallHint`**, core lengths). **`/run/bare-os/boot-perf.json`** schema **3** + **`BARE_OS_BOOT_BUDGET_STDLIB_*`** when bare-stdlib resolution exceeds **`BARE_OS_BOOT_BUDGET_MS_COLD`** / **`BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB`**. **`BARE_OS_SHELL_POSIX_MODE`** grouped **`( … )`** lists. **`bareOsTrySpawnHostSubprocess`** failures include **`errorCode`** / **`causeName`**. NDJSON / OTel string redaction helpers. **`scripts/sync-holepunch-clones.mjs`** NDJSON summary. **`docs/reference/posix-dashboard.md`** generated in pretest. |
| 1.39.0 | 0.1.0 | **`ctx.bareOsReadProtomuxExtensionsJson()`** and **`/proc/bare_os/protomux_extensions.json`** — operator registry snapshot + logical extension channel hints when **`BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY`** is set; default **`exposed:false`**. **`process_table.json`** schema **6** (**`jobControlSemantics`**). Syscalls: **`readv`**/**`writev`** (POSIX_FD_SIM pipes), **`getsockopt`**/**`setsockopt`** probes, **`fcntl`** lock cmds → **`EOPNOTSUPP`** object; **`posixXsh.namesCsv`** generated; **`errnoAlignment`** in **`syscalls.json`**. Protocol **`BARE_OS_POSIX_PROFILE_VERSION` `1.0.5`**. |
| 1.38.0 | 0.1.0 | **`/proc/bare_os/syscalls.json`** schema **5** + **cached** proc text (cleared with warm read cache); socket syscall **probes** (**`ENOSYS`**); **`/dev/shm`** segments; **`net_summary`** **`udxTuning`** / **`hyperswarmTuning`** env passthrough; **`bareOsCorestoreSnapshotHint`** → **`operator.corestore_snapshot_hint`** counter; **`bareOsPathconf`** **`_PC_NAME_MAX`** **128** under **`/dev/shm`**. With **`BARE_OS_PROC_BLIND_PEER_RELAY_HINTS`**, **`blind_relay_router`**, **`blind_pairing_sketch`**, and **`relay_geo_hint`** use **proc JSON schema 2** and merge env sketches with live **`swarm`** aggregates (peer count / lifecycle / **`relayGeoTier`** — no peer keys). |
| 1.37.0 | 0.1.0 | **`ctx.bareOsReadSnapshotHintsJson()`** mirrors **`/proc/bare_os/snapshot_hints.json`**; blind relay / pairing / geo **`/proc`** JSON stubbed unless **`BARE_OS_PROC_BLIND_PEER_RELAY_HINTS`**; passthrough **`BARE_OS_BARE_SUBPROCESS_BRIDGE`**, **`BARE_OS_BARE_SUBPROCESS_TIMEOUT_MS`**. |
| 1.36.0 | 0.1.0 | **`ctx.bareOsSendSignal`** negative target = synthetic **process group** (shell job **`pgid`**); **`ctx.bareOsReadReplicationOperatorJson`**, **`ctx.bareOsInvalidateWarmReadCaches`**, **`vfs.bareOsClearWarmReadCaches`**; **`bareOsVfsBatchWrite`** clears warm **`/bin`** / **`/lib/bare`** caches on matching puts; **`metrics_live.ipcTelemetry`** (FIFO quota / counters via **`BARE_OS_IPC_MAX_CHANNELS`**); swarm **`shouldAttemptPeer`** honors **`BARE_OS_PEER_ALLOWLIST_HEX`**; **`bareOsPathconf`** union/mirror **`_PC_NO_TRUNC`** / **`_PC_CHOWN_RESTRICTED`**; boot-ready **`subsystems.bareStdlib.resolutionWallMs`**. |
| 1.35.0 | 0.1.0 | **`ctx.bareOsSyscall('fcntl', …)`** (**`F_GETFL`** / **`F_SETFL`**, **`O_APPEND`** **`0x400`**, **`O_NONBLOCK`** **`0x800`**) + **`bareOsLogicalFdFlags`**; **`ctx.bareOsPosixPoll`** / **`bareOsPosixPollProbe`** + **`bareOsSyscall('posixPoll', …)`**; **`bareOsPosixFdSimRead`** honors **`O_NONBLOCK`** (**`EAGAIN`** when empty); **`/proc/bare_os/syscalls.json`** **`posixXsh.namesCsv`** includes **`poll`**; **`getconf`** **`BARE_OS_SYSCALL_OPS`** / **`BARE_OS_POSIX_XSH_OPS`** updated; protocol **`BARE_OS_POSIX_PROFILE_VERSION` `1.0.2`**. |
+273 -10
View File
@@ -144,6 +144,10 @@ import {
} from './lib/bare-os-wasm-kernel.js'
import { BARE_OS_CTX_API_VERSION } from './lib/bare-os-ctx-api.js'
import { buildBareOsPearCorestoreHrpcProcJson } from './lib/bare-os-proc-pear-corestore-hrpc.js'
import {
bareOsProcBlindPeerRelayHintsExposed,
buildBareOsBlindRelaySwarmRuntime
} from './lib/bare-os-proc-blind-peer-relay-gate.js'
import { buildBareOsRuntimeCaps } from './lib/bare-os-runtime-caps.js'
import {
bareOsBareModulesEnabled,
@@ -172,6 +176,7 @@ import { createHash } from 'bare-crypto'
import { buildBareOsHostProcJsonText } from './lib/bare-os-host-proc-snapshot.js'
import { computeReplicationSyncWindow } from './lib/bare-os-sync-window.js'
import { buildBareOsReplicationOperatorSurfaceProcJson } from './lib/bare-os-proc-replication-operator-surface.js'
import { buildBareOsReplicationLiveSketch } from './lib/bare-os-replication-proc-live.js'
import { buildBareOsBootGraphProcJson } from './lib/bare-os-boot-graph-proc.js'
import {
bareOsSecretHandleAcquire,
@@ -192,6 +197,7 @@ import {
import { bareOsSwarmLifecycleSnapshot } from './lib/bare-os-swarm-lifecycle.js'
import { bareOsReadHostProfile } from './lib/bare-os-host-profile.js'
import { bareOsProcessTableSnapshot } from './lib/bare-os-process-table.js'
import { buildBareOsProtomuxExtensionsProcJson } from './lib/bare-os-protomux-extensions-proc.js'
import { bareOsStatvfsFromHyperdrive } from './lib/bare-os-statvfs-from-drive.js'
import {
maybeBareOsBuildBinHyperbeeHint,
@@ -522,6 +528,7 @@ async function executeKernel(disk, store, swarm, initSource) {
'BARE_OS_BARE_SUBPROCESS_BRIDGE',
'BARE_OS_BARE_SUBPROCESS_TIMEOUT_MS',
'BARE_OS_PROC_BLIND_PEER_RELAY_HINTS',
'BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY',
'BARE_OS_FIND_EXEC_MAX',
'BARE_OS_XARGS_MAX_PROCS',
'BARE_OS_YES_MAX_LINES',
@@ -562,6 +569,7 @@ async function executeKernel(disk, store, swarm, initSource) {
'BARE_OS_SHELL_CMDSUBST_MAX_BYTES',
'BARE_OS_SHELL_LOOP_CONTROL',
'BARE_OS_SHELL_PIPEFAIL',
'BARE_OS_SHELL_POSIX_MODE',
'BARE_OS_TELEMETRY_NDJSON',
'BARE_OS_TELEMETRY_OTEL_JSONL',
'BARE_OS_PROC_POLL_MS',
@@ -593,6 +601,7 @@ async function executeKernel(disk, store, swarm, initSource) {
'BARE_OS_BOOT_POLICY_DIGEST_SKETCH',
'BARE_OS_KERNEL_STARTUP_CLASS',
'BARE_OS_BOOT_BUDGET_MS_COLD',
'BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB',
'BARE_OS_BOOT_CAPABILITY_CONTRACT_DEBUG',
'BARE_OS_BOOT_EXT_RESOLUTION_TRACE',
'BARE_OS_KERNEL_EXT_GRAPH',
@@ -908,6 +917,11 @@ async function executeKernel(disk, store, swarm, initSource) {
const warmReadCacheStatsRef = { current: null }
/** Cached `/proc/bare_os/syscalls.json` text; cleared with warm read cache invalidation. */
let bareOsSyscallsProcJsonCache = null
function bareOsBlindRelayRuntimeHintsForProc() {
if (!bareOsProcBlindPeerRelayHintsExposed(shellEnv)) return undefined
const peers = disk.peers ? [...disk.peers] : []
return { swarm: buildBareOsBlindRelaySwarmRuntime(shellEnv, peers) }
}
const vfs = createVfs(disk.drive, disk.personalDrive, shellEnv, vfsMountRef, {
warmReadCacheStatsRef,
procBareOsHostOsText() {
@@ -1022,7 +1036,11 @@ async function executeKernel(disk, store, swarm, initSource) {
return `${JSON.stringify(o)}\n`
},
procBareOsPearCorestoreHrpcJsonText(pearCorestoreHrpcProcId) {
const o = buildBareOsPearCorestoreHrpcProcJson(String(pearCorestoreHrpcProcId || ''), shellEnv)
const o = buildBareOsPearCorestoreHrpcProcJson(
String(pearCorestoreHrpcProcId || ''),
shellEnv,
bareOsBlindRelayRuntimeHintsForProc()
)
return `${JSON.stringify(o)}\n`
},
procBareOsBareRuntimeProtoMuxJsonText(bareRuntimeProtoMuxProcId) {
@@ -1054,11 +1072,19 @@ async function executeKernel(disk, store, swarm, initSource) {
return `${JSON.stringify(o)}\n`
},
procBareOsPearInspectLoggerTlsJsonText(pearInspectLoggerTlsProcId) {
const o = buildBareOsPearInspectLoggerTlsProcJson(String(pearInspectLoggerTlsProcId || ''), shellEnv)
const o = buildBareOsPearInspectLoggerTlsProcJson(
String(pearInspectLoggerTlsProcId || ''),
shellEnv,
bareOsBlindRelayRuntimeHintsForProc()
)
return `${JSON.stringify(o)}\n`
},
procBareOsHypercorePackHrpcLifecycleJsonText(hypercorePackHrpcLifecycleProcId) {
const o = buildBareOsHypercorePackHrpcLifecycleProcJson(String(hypercorePackHrpcLifecycleProcId || ''), shellEnv)
const o = buildBareOsHypercorePackHrpcLifecycleProcJson(
String(hypercorePackHrpcLifecycleProcId || ''),
shellEnv,
bareOsBlindRelayRuntimeHintsForProc()
)
return `${JSON.stringify(o)}\n`
},
procBareOsBootGraphJsonText() {
@@ -1683,6 +1709,7 @@ async function executeKernel(disk, store, swarm, initSource) {
return `${JSON.stringify({
topicHex: b4a.toString(tk, 'hex'),
peerCount: peers,
liveHyperdrive: buildBareOsReplicationLiveSketch(disk, peers),
session: sessionStatsRef,
mirrorHint: !!(mk && String(mk).trim()),
seedReplication: sr && typeof sr === 'object' ? sr : undefined,
@@ -2125,6 +2152,8 @@ async function executeKernel(disk, store, swarm, initSource) {
return metricsLiveCache.text
}
const pl = getBareOsPipelineLimits(shellEnv)
const peerRep = disk.peers?.size ?? 0
const repLive = buildBareOsReplicationLiveSketch(disk, peerRep)
metricsLiveCache = {
at: now,
text: `${JSON.stringify({
@@ -2134,7 +2163,14 @@ async function executeKernel(disk, store, swarm, initSource) {
coalesceMs: procPollMsResolved,
atMs: now,
session: { ...sessionStatsRef },
peers: disk.peers?.size ?? 0,
peers: peerRep,
replicationLive: {
schema: 1,
peerCount: peerRep,
systemCoreLength: repLive.systemCoreLength,
personalCoreLength: repLive.personalCoreLength,
stallHint: repLive.stallHint
},
pipeline: pl,
workerBudgetHints: {
schema: 1,
@@ -2172,7 +2208,8 @@ async function executeKernel(disk, store, swarm, initSource) {
sigactionHandlers:
liveCtx && liveCtx.bareOsLogicalSigaction
? liveCtx.bareOsLogicalSigaction
: null
: null,
env: shellEnv
})
})(),
initdReadiness: bareInitdReadinessSnapshot(),
@@ -2201,6 +2238,21 @@ async function executeKernel(disk, store, swarm, initSource) {
limitMs:
String(shellEnv.BARE_OS_BOOT_BUDGET_COLD_LIMIT_MS || '').trim() || null,
note: 'Guest kernel sets these when cold wall exceeds BARE_OS_BOOT_BUDGET_MS_COLD after boot-ready.'
},
bootBudgetBareStdlib: {
schema: 1,
resolutionWallMs:
String(shellEnv.BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS || '').trim() ||
null,
budgetMs:
String(shellEnv.BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB || '').trim() || null,
exceeded:
String(shellEnv.BARE_OS_BOOT_BUDGET_STDLIB_EXCEEDED || '') === '1',
wallMs:
String(shellEnv.BARE_OS_BOOT_BUDGET_STDLIB_WALL_MS || '').trim() || null,
limitMs:
String(shellEnv.BARE_OS_BOOT_BUDGET_STDLIB_LIMIT_MS || '').trim() || null,
note: 'Booter sets resolutionWallMs; guest sets exceeded when BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB is exceeded.'
}
})}\n`
}
@@ -2216,7 +2268,8 @@ async function executeKernel(disk, store, swarm, initSource) {
shellJobs,
ipcStats,
logicalFdRows: bareOsCollectLogicalFdRows(),
initdReadiness: bareInitdReadinessSnapshot()
initdReadiness: bareInitdReadinessSnapshot(),
env: shellEnv
})
)}\n`
},
@@ -2313,6 +2366,15 @@ async function executeKernel(disk, store, swarm, initSource) {
atMs: Date.now()
})}\n`
},
procBareOsProtomuxExtensionsText() {
return `${JSON.stringify(
buildBareOsProtomuxExtensionsProcJson({
env: shellEnv,
registrySnapshot: protomuxAliasRegistry.snapshot(),
ctxApiVersion: BARE_OS_CTX_API_VERSION
})
)}\n`
},
sysClassNetLoText() {
const n = disk.peers?.size ?? 0
return `operstate ${n > 0 ? 'unknown' : 'down'}\ncarrier ${n > 0 ? 1 : 0}\n`
@@ -2343,12 +2405,16 @@ async function executeKernel(disk, store, swarm, initSource) {
if (lockWarn.length) bootReadyStateRef.bareModuleLockWarnings = lockWarn
primeGlobalFetchFromBareLibrary(bareLibrary)
}
const bareStdlibWallMs = bareOsBareModulesEnabled(shellEnv)
? Date.now() - bareCtxResolutionT0
: 0
shellEnv.BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS = String(bareStdlibWallMs)
Object.assign(bootReadyStateRef.subsystems, {
bareStdlib: bareOsBareModulesEnabled(shellEnv)
? {
ready: true,
atMs: Date.now(),
resolutionWallMs: Date.now() - bareCtxResolutionT0,
resolutionWallMs: bareStdlibWallMs,
exportCount: Object.keys(bareLibrary).length
}
: {
@@ -3084,7 +3150,8 @@ async function executeKernel(disk, store, swarm, initSource) {
ipcStats,
logicalFdRows: bareOsCollectLogicalFdRows(),
initdReadiness: bareInitdReadinessSnapshot(),
sigactionHandlers: this.bareOsLogicalSigaction
sigactionHandlers: this.bareOsLogicalSigaction,
env: shellEnv
})
},
/**
@@ -3244,7 +3311,13 @@ async function executeKernel(disk, store, swarm, initSource) {
})
return { ok: true, child }
} catch (e) {
return { ok: false, reason: (e && e.message) || String(e) }
const msg = (e && e.message) || String(e)
return {
ok: false,
reason: msg,
errorCode: 'bare_subprocess_unavailable',
causeName: e && e.name ? String(e.name) : undefined
}
}
},
/**
@@ -3826,6 +3899,16 @@ async function executeKernel(disk, store, swarm, initSource) {
let cmd = args.cmd
if (typeof cmd === 'string') {
const u = String(cmd).toUpperCase()
if (u === 'F_GETLK' || u === 'F_SETLK' || u === 'F_SETLKW') {
return {
ok: false,
op: 'fcntl',
cmd: u,
code: 'EOPNOTSUPP',
errnoHint: 'EOPNOTSUPP',
note: 'Advisory file locks are not implemented; use VFS cooperative patterns.'
}
}
if (u === 'F_GETFL' || u === 'GETFL') cmd = 3
else if (u === 'F_SETFL' || u === 'SETFL') cmd = 4
else {
@@ -3943,6 +4026,117 @@ async function executeKernel(disk, store, swarm, initSource) {
current: Number.isFinite(nowMask) ? nowMask : 0o022
}
}
if (name === 'readv') {
const fd = Number(args.fd)
if (!Number.isFinite(fd)) {
throw new Error('bareOsSyscall: readv: fd is required')
}
const iovs = Array.isArray(args.iovs) ? args.iovs : []
const maxIovs = 16
const maxPer = 65536
const maxTotal = 1024 * 1024
let totalBytes = 0
/** @type {string[]} */
const buffers = []
for (const iov of iovs.slice(0, maxIovs)) {
const want = Math.min(
maxPer,
Math.max(
0,
Math.floor(
Number(
iov && typeof iov === 'object' && 'length' in iov
? iov.length
: iov && typeof iov === 'object' && 'maxBytes' in iov
? iov.maxBytes
: 4096
)
)
)
)
if (want <= 0) {
buffers.push('')
continue
}
if (totalBytes + want > maxTotal) {
throw new Error('bareOsSyscall: readv: total iov budget exceeded')
}
const r = this.bareOsPosixFdSimRead(fd, want)
if (!r || !r.ok) {
if (r && r.reason === 'EAGAIN') {
const err = /** @type {Error & { code?: string }} */ (
new Error('EAGAIN: readv')
)
err.code = 'EAGAIN'
throw err
}
throw new Error(
'bareOsSyscall: readv: ' + (r && r.reason ? r.reason : 'failed')
)
}
const chunk = String(r.data || '')
buffers.push(chunk)
totalBytes += b4a.from(chunk, 'utf8').byteLength
if (chunk.length < want) break
}
return { ok: true, op: 'readv', fd, buffers, bytesRead: totalBytes }
}
if (name === 'writev') {
const fd = Number(args.fd)
if (!Number.isFinite(fd)) {
throw new Error('bareOsSyscall: writev: fd is required')
}
const bufs = Array.isArray(args.buffers) ? args.buffers : []
const maxChunks = 64
const maxTotal = 1024 * 1024
const pieces = []
let n = 0
for (const b of bufs.slice(0, maxChunks)) {
const s =
typeof b === 'string'
? b
: b instanceof Uint8Array
? b4a.toString(b, 'utf8')
: String(b)
const add = b4a.from(s, 'utf8').byteLength
n += add
if (n > maxTotal) {
throw new Error('bareOsSyscall: writev: total length exceeded')
}
pieces.push(s)
}
const payload = pieces.join('')
const w = this.bareOsPosixFdSimWrite(fd, payload)
if (!w || !w.ok) {
if (w && w.reason === 'EAGAIN') {
const err = /** @type {Error & { code?: string }} */ (
new Error('EAGAIN: writev')
)
err.code = 'EAGAIN'
throw err
}
throw new Error(
'bareOsSyscall: writev: ' + (w && w.reason ? w.reason : 'failed')
)
}
return {
ok: true,
op: 'writev',
fd,
bytesWritten: w.bytes ?? b4a.from(payload, 'utf8').byteLength
}
}
if (name === 'getsockopt' || name === 'setsockopt') {
return {
ok: false,
op: name,
code: 'ENOSYS',
errnoHint: 'ENOSYS',
posixAlignment: 'ENOTSUP',
note:
'Socket option syscalls are not kernel FDs in Bare OS; use ctx.bare networking modules.'
}
}
if (
name === 'socket' ||
name === 'bind' ||
@@ -3999,7 +4193,45 @@ async function executeKernel(disk, store, swarm, initSource) {
*/
async bareOsVfsBatchWrite(puts) {
await bareOsVfsBatchPut(disk.drive, puts)
if (vfs?.bareOsClearWarmReadCaches && Array.isArray(puts)) {
if (!vfs || !Array.isArray(puts)) return
let hasManifestPut = false
/** @type {Uint8Array | ArrayBuffer | ArrayBufferView | null | undefined} */
let manifestBuf = null
let hasOtherWarmPut = false
for (const row of puts) {
const p = String(row?.path || '').replace(/^\/+/, '')
if (p === 'lib/bare/bare-module-manifest.json') {
hasManifestPut = true
manifestBuf = row?.buf
} else if (
p === 'bin' ||
p.startsWith('bin/') ||
p === 'lib/bare' ||
p.startsWith('lib/bare/')
) {
hasOtherWarmPut = true
break
}
}
if (
hasManifestPut &&
!hasOtherWarmPut &&
manifestBuf != null &&
typeof vfs.bareOsEvictLibBareBundlesFromManifest === 'function'
) {
const u8 =
manifestBuf instanceof Uint8Array
? manifestBuf
: new Uint8Array(
manifestBuf instanceof ArrayBuffer
? manifestBuf
: /** @type {ArrayBufferView} */ (manifestBuf).buffer
)
vfs.bareOsEvictLibBareBundlesFromManifest(u8)
bareOsKernelMetricInc('vfs.warm_read_cache_invalidate_batch_manifest')
return
}
if (typeof vfs.bareOsClearWarmReadCaches === 'function') {
for (const row of puts) {
const p = String(row?.path || '').replace(/^\/+/, '')
if (
@@ -4089,6 +4321,17 @@ async function executeKernel(disk, store, swarm, initSource) {
if (handles.length) o.snapshot_handles = handles
return o
},
/**
* Same object as `/proc/bare_os/protomux_extensions.json` (gated by `BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY`).
* @returns {Record<string, unknown>}
*/
bareOsReadProtomuxExtensionsJson() {
return buildBareOsProtomuxExtensionsProcJson({
env: shellEnv,
registrySnapshot: protomuxAliasRegistry.snapshot(),
ctxApiVersion: BARE_OS_CTX_API_VERSION
})
},
bareOsVaultAuditSummary() {
const c = bareOsInteractiveCtxRef.ctx
const id = c && c.identity
@@ -4201,6 +4444,26 @@ async function executeKernel(disk, store, swarm, initSource) {
bareOsKernelMetricInc('vfs.warm_read_cache_invalidate_explicit')
return { ok: true, reason: String(reason || '').slice(0, 256) }
},
/**
* Evict `/lib/bare` warm-cache rows using a `bare-module-manifest.json` payload
* (same selective path as `bareOsVfsBatchWrite` manifest-only puts).
* @param {Uint8Array | ArrayBuffer} buf
*/
bareOsInvalidateWarmReadCachesFromBareManifestJson(buf) {
if (
vfs &&
typeof vfs.bareOsEvictLibBareBundlesFromManifest === 'function' &&
buf
) {
const u8 =
buf instanceof Uint8Array ? buf : new Uint8Array(/** @type {ArrayBuffer} */ (buf))
vfs.bareOsEvictLibBareBundlesFromManifest(u8)
} else if (vfs && typeof vfs.bareOsClearWarmReadCaches === 'function') {
vfs.bareOsClearWarmReadCaches()
}
bareOsKernelMetricInc('vfs.warm_read_cache_invalidate_manifest_ctx')
return { ok: true }
},
/**
* Batch-read `/proc/bare_os/*` mirrors for baretop(1). Keys must stay aligned with
* `BARE_TOP_SNAPSHOT_PROC_ENTRIES` in packages/bare-os-coreutils/lib/baretop-snapshot.js.
@@ -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.38.0'
export const BARE_OS_CTX_API_VERSION = '1.40.0'
+5
View File
@@ -134,6 +134,9 @@ export interface BareOsKernelContext {
bareOsInvalidateWarmReadCaches?(
reason?: string
): { ok: boolean; reason: string }
bareOsInvalidateWarmReadCachesFromBareManifestJson?(
buf: Uint8Array | ArrayBuffer
): { ok: boolean }
/**
* Optional batch `/proc/bare_os/*` read for baretop(1); keys match baretop-snapshot preamble.
*/
@@ -445,6 +448,8 @@ export interface BareOsKernelContext {
}
/** Corestore snapshot-style hints (same object as `/proc/bare_os/snapshot_hints.json`). */
bareOsReadSnapshotHintsJson?(): Record<string, unknown>
/** Protomux extension registry mirror (`/proc/bare_os/protomux_extensions.json`); gated by env. */
bareOsReadProtomuxExtensionsJson?(): Record<string, unknown>
bareOsVaultAuditSummary?(): {
schema: number
identityState: string
@@ -1,3 +1,5 @@
import { bareOsSwarmLifecycleSnapshot } from './bare-os-swarm-lifecycle.js'
/**
* Gate blind-peer / relay operator JSON under `/proc/bare_os` (non-secret sketches only).
* Default off so images do not advertise topology unless the operator opts in.
@@ -20,3 +22,29 @@ export function bareOsProcBlindPeerRelayHintsStub(atMs) {
atMs
}
}
/**
* Non-secret swarm-derived hints for blind-relay / pairing / geo proc JSON when hints are exposed.
* No peer keys, addresses, or topic material — only counts and lifecycle classification.
* @param {Record<string, string | undefined>} env
* @param {Array<{ id?: unknown }>} peers
*/
export function buildBareOsBlindRelaySwarmRuntime(env, peers) {
const peerCount = Array.isArray(peers) ? peers.length : 0
const lifecycle = bareOsSwarmLifecycleSnapshot(env, peerCount)
/** @type {'isolated' | 'single_peer' | 'multi_peer'} */
let relayGeoTier = 'isolated'
if (peerCount === 1) relayGeoTier = 'single_peer'
else if (peerCount > 1) relayGeoTier = 'multi_peer'
return {
schema: 1,
peerCount,
relayGeoTier,
pairingSurfaceReady: peerCount > 0,
lifecycle,
note:
'Aggregates peer count and swarm lifecycle only; merge with env-injected operator JSON. No DHT keys or peer identities.',
atMs: Date.now()
}
}
@@ -9,8 +9,9 @@ import {
* Aligns with seed RPC word 11 + bits11 — no Node `node:*` built-ins in guest paths.
* @param {string} id
* @param {Record<string, string>} env
* @param {{ swarm?: Record<string, unknown> | null }} [runtimeHints]
*/
export function buildBareOsHypercorePackHrpcLifecycleProcJson(id, env) {
export function buildBareOsHypercorePackHrpcLifecycleProcJson(id, env, runtimeHints) {
const now = Date.now()
const esc = (k) => String(env[k] ?? '').trim()
@@ -122,9 +123,11 @@ export function buildBareOsHypercorePackHrpcLifecycleProcJson(id, env) {
return bareOsProcBlindPeerRelayHintsStub(now)
}
return {
schema: 1,
schema: 2,
exposed: true,
regions: parseJsonEnv('BARE_OS_RELAY_GEO_HINT_JSON'),
note: 'coarse relay region tags.',
swarm: runtimeHints?.swarm ?? null,
note: 'Coarse relay region tags from env plus swarm aggregates (no geo-IP; peer count tier only).',
atMs: now
}
case 'bare_pack_cache':
@@ -7,8 +7,9 @@ import {
* Capability word 7 optional `/proc/bare_os/*.json` payloads (env-injected; bounded, non-secret).
* @param {string} id
* @param {Record<string, string>} env
* @param {{ swarm?: Record<string, unknown> | null }} [runtimeHints]
*/
export function buildBareOsPearCorestoreHrpcProcJson(id, env) {
export function buildBareOsPearCorestoreHrpcProcJson(id, env, runtimeHints) {
const now = Date.now()
const esc = (k) => String(env[k] ?? '').trim()
@@ -106,9 +107,11 @@ export function buildBareOsPearCorestoreHrpcProcJson(id, env) {
return bareOsProcBlindPeerRelayHintsStub(now)
}
return {
schema: 1,
schema: 2,
exposed: true,
router: parseJsonEnv('BARE_OS_BLIND_RELAY_ROUTER_JSON'),
note: 'Topology sketch from blind-peer-router patterns.',
swarm: runtimeHints?.swarm ?? null,
note: 'Env router sketch plus live swarm aggregates (peer count / lifecycle) when runtimeHints supplied from booter.',
atMs: now
}
case 'autopass_session_sketch':
@@ -8,8 +8,9 @@ import {
* Maps Holepunch `bare-*` / `pear-*` stacks — no Node `node:*` built-ins in guest paths.
* @param {string} id
* @param {Record<string, string>} env
* @param {{ swarm?: Record<string, unknown> | null }} [runtimeHints]
*/
export function buildBareOsPearInspectLoggerTlsProcJson(id, env) {
export function buildBareOsPearInspectLoggerTlsProcJson(id, env, runtimeHints) {
const now = Date.now()
const esc = (k) => String(env[k] ?? '').trim()
@@ -145,9 +146,11 @@ export function buildBareOsPearInspectLoggerTlsProcJson(id, env) {
return bareOsProcBlindPeerRelayHintsStub(now)
}
return {
schema: 1,
schema: 2,
exposed: true,
sketch: parseJsonEnv('BARE_OS_BLIND_PAIRING_SKETCH_JSON'),
note: 'blind-pairing operator sketch.',
swarm: runtimeHints?.swarm ?? null,
note: 'Env pairing sketch plus live swarm aggregates when booter supplies runtimeHints.',
atMs: now
}
case 'broadcast_encryption_hint':
@@ -11,7 +11,8 @@
* ipcStats?: { processGroups?: Record<string, unknown> } | null,
* logicalFdRows?: Array<{ fd: number, target: string }>,
* initdReadiness?: { units?: Array<{ name: string, phase: string, startedAtMs: number, error?: string }>, schema?: number } | null,
* sigactionHandlers?: Record<string, string> | null
* sigactionHandlers?: Record<string, string> | null,
* env?: Record<string, string | undefined> | null
* }} opts
*/
export function bareOsProcessTableSnapshot(opts = {}) {
@@ -98,6 +99,14 @@ export function bareOsProcessTableSnapshot(opts = {}) {
? opts.sigactionHandlers
: null
const env = opts.env && typeof opts.env === 'object' ? opts.env : {}
const pipefailOn =
env.BARE_OS_SHELL_PIPEFAIL === '1' ||
env.BARE_OS_SHELL_PIPEFAIL === 'true'
const posixModeOn =
env.BARE_OS_SHELL_POSIX_MODE === '1' ||
env.BARE_OS_SHELL_POSIX_MODE === 'true'
const initd = opts.initdReadiness
const initdUnitsRaw =
initd && Array.isArray(initd.units) ? initd.units : []
@@ -168,9 +177,9 @@ export function bareOsProcessTableSnapshot(opts = {}) {
}))
return {
schema: 5,
schemaVersion: 5,
note: 'Synthetic rows; Bare OS guests do not expose host OS processes. v5 adds parentName and initdUnitName for POSIX-like ps trees.',
schema: 6,
schemaVersion: 6,
note: 'Synthetic rows; Bare OS guests do not expose host OS processes. v6 adds jobControlSemantics (pipefail / posix mode env mirrors). v5 parentName/initd rows unchanged.',
signalModel: {
schema: 1,
note: 'Virtual deliveries via ctx.bareOsSendSignal (not full sigaction/sigprocmask).',
@@ -217,6 +226,16 @@ export function bareOsProcessTableSnapshot(opts = {}) {
killpgAnalog:
'Negative numeric targets index **`shellBackgroundJobs`** by **`pgid`**; active jobs only (zombies excluded except **`kill -0`** existence checks). Not a full killpg(2) emulation.'
},
jobControlSemantics: {
schema: 1,
pipefail: pipefailOn,
posixShellMode: posixModeOn,
pipelineExitRule: pipefailOn
? 'first_failing_stage_in_pipeline'
: 'last_stage_posix_default',
waitReapsCompletedJobs: true,
note: 'Mirrors BARE_OS_SHELL_PIPEFAIL and BARE_OS_SHELL_POSIX_MODE; see handbook ch.9 §3.'
},
ipcProcessGroups:
opts.ipcStats &&
opts.ipcStats.processGroups &&
@@ -0,0 +1,57 @@
/**
* `/proc/bare_os/protomux_extensions.json` — policy-gated operator view of Protomux
* channel hints for kernel extensions (no wire secrets).
*/
/**
* @param {Record<string, string | undefined>} env
*/
function protomuxExtensionsRegistryExposed(env) {
const v = String(env?.BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY ?? '')
.trim()
.toLowerCase()
return v === '1' || v === 'true' || v === 'yes'
}
/**
* @param {{
* env?: Record<string, string | undefined> | null,
* registrySnapshot?: Record<string, unknown> | null,
* ctxApiVersion?: string
* }} opts
*/
export function buildBareOsProtomuxExtensionsProcJson(opts = {}) {
const env = opts.env && typeof opts.env === 'object' ? opts.env : {}
const now = Date.now()
if (!protomuxExtensionsRegistryExposed(env)) {
return {
schema: 1,
exposed: false,
note:
'Set BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY=1 to expose extension mux hints (alias registry snapshot + stable logical channel names).',
atMs: now
}
}
const snap =
opts.registrySnapshot && typeof opts.registrySnapshot === 'object'
? opts.registrySnapshot
: {}
return {
schemaVersion: 1,
exposed: true,
ctxApiVersion: String(opts.ctxApiVersion || ''),
registry: snap,
extensionLogicalChannels: [
{
name: 'bare-os-kernel-ext-handshake',
note: 'Reserved logical label for extension pairing over Protomux-framed streams (P2P).'
},
{
name: 'bare-os-extension-telemetry',
note: 'Optional NDJSON-shaped diagnostic channel; host must open explicitly.'
}
],
wireReference: '/proc/bare_os/protomux.json',
atMs: now
}
}
@@ -0,0 +1,42 @@
/**
* Live Hyperdrive / core length hints for `/proc/bare_os/replication` and
* `metrics_live.replicationLive` (non-secret progress; not full per-peer throughput).
*
* @param {{ drive?: unknown, personalDrive?: unknown } | null | undefined} disk
* @param {number} peerCount
*/
export function buildBareOsReplicationLiveSketch(disk, peerCount) {
let systemCoreLength = null
let personalCoreLength = null
try {
const c =
disk &&
disk.drive &&
/** @type {{ core?: { length?: number } }} */ (disk.drive).core
if (c && typeof c.length === 'number') systemCoreLength = c.length
} catch {
systemCoreLength = null
}
try {
const c =
disk &&
disk.personalDrive &&
/** @type {{ core?: { length?: number } }} */ (disk.personalDrive).core
if (c && typeof c.length === 'number') personalCoreLength = c.length
} catch {
personalCoreLength = null
}
const stallHint =
peerCount === 0
? 'no_peers'
: systemCoreLength == null
? 'length_unavailable'
: 'ok'
return {
schema: 1,
systemCoreLength,
personalCoreLength,
stallHint,
note: 'Append-only core lengths are non-secret progress hints; not a full replication telemetry plane.'
}
}
@@ -105,6 +105,44 @@ export const BARE_OS_SYSCALL_OPS_DETAIL = Object.freeze([
posixAlignment: 'ENOTSUP',
mapsTo: ['stream.end / destroy'],
errnoHint: 'ENOSYS'
},
{
name: 'getsockopt',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['kernel socket FDs not exposed; use ctx.bare / swarm'],
errnoHint: 'ENOSYS'
},
{
name: 'setsockopt',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['kernel socket FDs not exposed; use ctx.bare / swarm'],
errnoHint: 'ENOSYS'
},
{
name: 'readv',
category: 'fs',
stability: 'experimental',
posixAlignment: 'partial',
mapsTo: [
'ctx.bareOsSyscall("readv")',
'bounded sequential reads from posix-pipe read FD (BARE_OS_POSIX_FD_SIM)'
],
errnoHint: 'EINVAL'
},
{
name: 'writev',
category: 'fs',
stability: 'experimental',
posixAlignment: 'partial',
mapsTo: [
'ctx.bareOsSyscall("writev")',
'bounded concatenated write to posix-pipe write FD (BARE_OS_POSIX_FD_SIM)'
],
errnoHint: 'EINVAL'
}
])
@@ -153,6 +191,38 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
mapsTo: ['vfs.writeFile', 'ctx.bareOsBinWrite', 'IPC fifo producer'],
errnoHint: 'EIO'
},
{
name: 'readv',
category: 'fs',
stability: 'experimental',
posixAlignment: 'partial',
mapsTo: ['ctx.bareOsSyscall("readv")', 'posix-pipe read FD', 'bounded iovec count'],
errnoHint: 'EINVAL'
},
{
name: 'writev',
category: 'fs',
stability: 'experimental',
posixAlignment: 'partial',
mapsTo: ['ctx.bareOsSyscall("writev")', 'posix-pipe write FD', 'bounded total bytes'],
errnoHint: 'EINVAL'
},
{
name: 'getsockopt',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("getsockopt")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'setsockopt',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("setsockopt")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'lseek',
category: 'fs',
@@ -194,6 +264,10 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
'ctx.bareOsSyscall("fcntl")',
'F_GETFL',
'F_SETFL',
'F_GETLK',
'F_SETLK',
'F_SETLKW',
'file locks return EOPNOTSUPP object (not thrown)',
'O_APPEND',
'O_NONBLOCK',
'bareOsLogicalFdFlags'
@@ -223,6 +297,70 @@ export const BARE_OS_POSIX_XSH_OPS_DETAIL = Object.freeze([
posixAlignment: 'partial',
mapsTo: ['vfs.env.UMASK octal', 'umask shell builtin'],
errnoHint: 'EINVAL'
},
{
name: 'socket',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("socket")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'bind',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("bind")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'listen',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("listen")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'accept',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("accept")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'connect',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("connect")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'send',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("send")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'recv',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("recv")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
},
{
name: 'shutdown',
category: 'ipc',
stability: 'experimental',
posixAlignment: 'ENOTSUP',
mapsTo: ['ctx.bareOsSyscall("shutdown")', 'ENOSYS-shaped probe'],
errnoHint: 'ENOSYS'
}
])
@@ -7,7 +7,8 @@ import {
} from 'bare-os-protocol/bare-os-posix-profile.js'
import {
BARE_OS_SYSCALL_OPS_DETAIL_FULL,
BARE_OS_STOCK_SYSCALL_OPS
BARE_OS_STOCK_SYSCALL_OPS,
bareOsPosixXshOpsCsv
} from './bare-os-syscall-ops.js'
import { BARE_OS_POSIX_SIGNAL_NAMES } from './bare-os-posix-signals.js'
import { bareOsErrnoTableForProc } from './bare-os-posix-errno.js'
@@ -28,9 +29,8 @@ export function buildBareOsSyscallsProcJson(p) {
opsDetail: [...BARE_OS_SYSCALL_OPS_DETAIL_FULL],
posixXsh: {
schema: 1,
note: 'POSIX.1 XSH-style names: logical names in opsDetail; socket family are ctx.bareOsSyscall ops returning ENOSYS-shaped results (not kernel socket FDs).',
namesCsv:
'open,close,read,write,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,shutdown'
note: 'POSIX.1 XSH-style names: logical names in opsDetail; socket family are ctx.bareOsSyscall ops returning ENOSYS-shaped results (not kernel socket FDs). readv/writev are partial posix-pipe facades; getsockopt/setsockopt are ENOSYS-shaped probes.',
namesCsv: bareOsPosixXshOpsCsv()
},
errnoHints: bareOsErrnoTableForProc(),
fdModel: {
@@ -39,7 +39,7 @@ export function buildBareOsSyscallsProcJson(p) {
stdio: [0, 1, 2],
register: 'ctx.bareOsRegisterLogicalFd',
processTablePath: '/proc/bare_os/process_table.json',
processTableSchema: 5,
processTableSchema: 6,
posixLike: {
schema: 1,
note: 'POSIX open/read/write/close/pipe/dup/fcntl analogs; see docs/architecture/POSIX_DECLARED_PROFILE.md.',
@@ -107,6 +107,12 @@ export function buildBareOsSyscallsProcJson(p) {
caps: {
note: 'VFS path classes and boot policy may deny individual ops at runtime.'
},
errnoAlignment: {
schema: 1,
note: 'errnoHints use Linux/x86-64-style integers (same family as libuv / Holepunch bare-fs binding errors). Logical FD simulation uses EBADF, EAGAIN, EINVAL, ENOSYS, EOPNOTSUPP consistently with bare-os-posix-errno.js.',
openFlagsNote:
'fcntl O_APPEND (0x400) and O_NONBLOCK (0x800) match the masks used by bare-fs open flags on the host when translating to guest logical FDs.'
},
atMs: Date.now()
}
}
+33 -2
View File
@@ -29,6 +29,31 @@ const README_TEXT = `Bare OS session logs (mirrored on your personal drive under
audit.log — optional execLine audit when BARE_OS_AUDIT=1
`
/**
* Strip long hex / obvious secret-shaped tokens from telemetry mirrors (best-effort).
* @param {string} s
*/
function bareOsTelemetryRedactString(s) {
return String(s)
.replace(/\b[0-9a-f]{128,}\b/gi, '<redacted_hex>')
.replace(/\bBearer\s+\S+/gi, 'Bearer <redacted>')
.replace(/\bsk-[a-zA-Z0-9]{16,}\b/g, '<redacted_sk>')
}
/**
* @param {Record<string, unknown>} rec
*/
function bareOsTelemetrySanitizeRec(rec) {
if (!rec || typeof rec !== 'object') return {}
/** @type {Record<string, unknown>} */
const o = {}
for (const [k, v] of Object.entries(rec)) {
if (typeof v === 'string') o[k] = bareOsTelemetryRedactString(v)
else o[k] = v
}
return o
}
/** Max size before trimming older log bytes (best-effort). */
const LOG_MAX_BYTES = 512 * 1024
@@ -118,6 +143,9 @@ async function mirrorBareOsTelemetryNdjson(ctx, rec) {
const pearInspectLoggerTlsProbeId = String(env.BARE_OS_PROBE_ID_PEAR_INSPECT_LOGGER_TLS || '').trim()
const hypercorePackHrpcLifecycleProbeId = String(env.BARE_OS_PROBE_ID_HYPERCORE_PACK_HRPC_LIFECYCLE || '').trim()
const traceId = String(env.BARE_OS_TRACE_ID || '').trim()
const safeRec = bareOsTelemetrySanitizeRec(
/** @type {Record<string, unknown>} */ (rec)
)
const line =
JSON.stringify({
telemetrySchemaVersion: BARE_OS_TELEMETRY_SCHEMA_VERSION,
@@ -144,7 +172,7 @@ async function mirrorBareOsTelemetryNdjson(ctx, rec) {
)
return Number.isFinite(n) ? Math.min(1e6, n) : undefined
})(),
...rec
...safeRec
}) + '\n'
const chunk = ctx.b4a.from(line)
const prev = await vfs.readFile(dest)
@@ -176,6 +204,9 @@ async function mirrorBareOsOtelJsonl(ctx, eventName, attrs) {
if (!dest.startsWith('/') && !dest.startsWith('~/')) return
const vfs = ctx.vfs
if (!vfs || typeof vfs.readFile !== 'function') return
const safeAttrs = bareOsTelemetrySanitizeRec(
/** @type {Record<string, unknown>} */ (attrs)
)
const line =
JSON.stringify({
otlSchemaVersion: 8,
@@ -202,7 +233,7 @@ async function mirrorBareOsOtelJsonl(ctx, eventName, attrs) {
events: [],
links: [],
exemplars: [],
attributes: Object.entries(attrs).map(([k, v]) => ({
attributes: Object.entries(safeAttrs).map(([k, v]) => ({
key: k,
value:
typeof v === 'string'
+32
View File
@@ -2272,6 +2272,38 @@ function tryExecShellDeclareBuiltin(ctx, rest) {
async function dispatchShellStatement(ctx, stmt) {
const head = stmt[0]
const shEnv = ctx.vfs?.env
const posixMode =
shEnv &&
(shEnv.BARE_OS_SHELL_POSIX_MODE === '1' ||
shEnv.BARE_OS_SHELL_POSIX_MODE === 'true')
if (posixMode && head?.type === 'op' && head.value === '(') {
let depth = 0
let close = -1
for (let j = 0; j < stmt.length; j++) {
const t = stmt[j]
if (t.type === 'op' && t.value === '(') depth++
else if (t.type === 'op' && t.value === ')') {
depth--
if (depth === 0) {
close = j
break
}
}
}
if (close < 0) {
ctx.console.error('shell: POSIX mode: unmatched (')
ctx.exitCode = 2
return 'ok'
}
if (close !== stmt.length - 1) {
ctx.console.error(
'shell: POSIX mode: grouped list must span the full statement'
)
ctx.exitCode = 2
return 'ok'
}
return execSemicolonLists(ctx, stmt.slice(1, close))
}
const localOn =
shEnv &&
(shEnv.BARE_OS_SHELL_LOCAL_DECLARE === '1' ||
+97
View File
@@ -362,6 +362,7 @@ export const BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE = Object.free
* procBareOsSyscallsText?: () => string,
* procBareOsMetricsPromText?: () => string,
* procBareOsProtomuxWireText?: () => string,
* procBareOsProtomuxExtensionsText?: () => string,
* procBareOsNetSummaryText?: () => string,
* procBareOsExtensionsText?: () => string,
* procBareOsHdmsHintsText?: () => string,
@@ -565,6 +566,10 @@ export function createVfs(
typeof vfsOptions.procBareOsProtomuxWireText === 'function'
? vfsOptions.procBareOsProtomuxWireText
: null
const procBareOsProtomuxExtensionsText =
typeof vfsOptions.procBareOsProtomuxExtensionsText === 'function'
? vfsOptions.procBareOsProtomuxExtensionsText
: null
const procBareOsNetSummaryText =
typeof vfsOptions.procBareOsNetSummaryText === 'function'
? vfsOptions.procBareOsNetSummaryText
@@ -799,6 +804,72 @@ export function createVfs(
bareOsKernelMetricInc('vfs.warm_read_cache_clear')
}
/** @param {string} absFollowed */
function bareOsEvictSingleWarmReadPath(absFollowed) {
if (!isWarmReadCachePath(absFollowed)) return
if (binReadCache) binReadCache.delete(absFollowed)
if (binDigestCache && binPathToBlakeDigest && binDigestRefcount) {
const oldHex = binPathToBlakeDigest.get(absFollowed)
if (oldHex) {
binPathToBlakeDigest.delete(absFollowed)
const n0 = (binDigestRefcount.get(oldHex) || 1) - 1
if (n0 <= 0) {
binDigestRefcount.delete(oldHex)
binDigestCache.delete(oldHex)
} else {
binDigestRefcount.set(oldHex, n0)
}
}
}
if (binBlake2bLruPaths) {
const i = binBlake2bLruPaths.indexOf(absFollowed)
if (i >= 0) binBlake2bLruPaths.splice(i, 1)
}
}
/**
* Invalidate warm-cache entries for `bare-module-manifest.json` and bundled
* `/lib/bare/bundles/<ctxKey>.js` rows (parse errors fall back to full clear).
* @param {Uint8Array | ArrayBuffer} buf
*/
function bareOsEvictLibBareBundlesFromManifest(buf) {
const u8 =
buf instanceof Uint8Array ? buf : new Uint8Array(/** @type {ArrayBuffer} */ (buf))
let text
try {
text = new TextDecoder().decode(u8)
} catch {
bareOsClearWarmReadCaches()
return
}
/** @type {unknown} */
let o
try {
o = JSON.parse(text)
} catch {
bareOsClearWarmReadCaches()
return
}
if (
!o ||
typeof o !== 'object' ||
!Array.isArray(/** @type {{ entries?: unknown }} */ (o).entries)
) {
bareOsClearWarmReadCaches()
return
}
bareOsEvictSingleWarmReadPath('/lib/bare/bare-module-manifest.json')
for (const e of /** @type {{ entries: unknown[] }} */ (o).entries) {
if (!e || typeof e !== 'object') continue
const ent = /** @type {{ bundle?: boolean, ctxKey?: string }} */ (e)
if (ent.bundle !== true) continue
const ck = String(ent.ctxKey || '').trim()
if (!ck) continue
bareOsEvictSingleWarmReadPath(`/lib/bare/bundles/${ck}.js`)
}
bareOsKernelMetricInc('vfs.warm_read_cache_evict_manifest')
}
const sysClassNetLoText =
typeof vfsOptions.sysClassNetLoText === 'function'
? vfsOptions.sysClassNetLoText
@@ -1321,6 +1392,12 @@ export function createVfs(
: '{"schemaVersion":1,"aliases":{}}\n'
return utf8Encode(t)
}
if (f === 'bare_os_protomux_extensions') {
const t = procBareOsProtomuxExtensionsText
? procBareOsProtomuxExtensionsText()
: '{"schema":1,"exposed":false}\n'
return utf8Encode(t)
}
if (f === 'bare_os_net_summary') {
const t = procBareOsNetSummaryText
? procBareOsNetSummaryText()
@@ -1528,6 +1605,10 @@ export function createVfs(
name: 'protomux.json',
path: '/proc/bare_os/protomux.json'
},
{
name: 'protomux_extensions.json',
path: '/proc/bare_os/protomux_extensions.json'
},
{
name: 'net_summary.json',
path: '/proc/bare_os/net_summary.json'
@@ -2226,6 +2307,8 @@ export function createVfs(
'metrics.prom': 'bare_os_metrics_prom',
protomux: 'bare_os_protomux_wire',
'protomux.json': 'bare_os_protomux_wire',
protomux_extensions: 'bare_os_protomux_extensions',
'protomux_extensions.json': 'bare_os_protomux_extensions',
net_summary: 'bare_os_net_summary',
'net_summary.json': 'bare_os_net_summary',
host_os: 'bare_os_host_os',
@@ -2688,6 +2771,17 @@ export function createVfs(
file: 'bare_os_protomux_wire'
}
}
if (
sub === 'bare_os_protomux_extensions' ||
sub === 'bare_os_protomux_extensions.json'
) {
return {
virtualPseudo: true,
kind: 'proc',
node: 'file',
file: 'bare_os_protomux_extensions'
}
}
if (
sub === 'bare_os_net_summary' ||
sub === 'bare_os_net_summary.json'
@@ -3908,6 +4002,7 @@ export function createVfs(
'bare_os_protomux_channels.json',
'bare_os_protomux_rpc_pool_health.json',
'bare_os_protomux_wire.json',
'bare_os_protomux_extensions.json',
'bare_os_provenance',
'bare_os_quotas',
'bare_os_react_native_bare_kit.json',
@@ -4076,6 +4171,7 @@ export function createVfs(
'protomux_channels.json',
'protomux_rpc_pool_health.json',
'protomux.json',
'protomux_extensions.json',
'provenance',
'quotas',
'react_native_bare_kit.json',
@@ -4460,6 +4556,7 @@ export function createVfs(
env,
bareOsClearWarmReadCaches,
bareOsEvictLibBareBundlesFromManifest,
async chdir(userPath) {
const abs = resolveLogical(userPath)
+157 -6
View File
@@ -92,6 +92,8 @@ import {
import { parseUnitDropInText } from './lib/bare-initd-user.js'
import { bareOsProcessTableSnapshot } from './lib/bare-os-process-table.js'
import { buildBareOsSyscallsProcJson } from './lib/bare-os-syscalls-proc-json.js'
import { buildBareOsProtomuxExtensionsProcJson } from './lib/bare-os-protomux-extensions-proc.js'
import { buildBareOsReplicationLiveSketch } from './lib/bare-os-replication-proc-live.js'
import { buildBareOsReplicationOperatorSurfaceProcJson } from './lib/bare-os-proc-replication-operator-surface.js'
import {
DEFAULT_CURL_USER_AGENT,
@@ -1072,6 +1074,55 @@ test('vfs /bin warm read cache hit then bareOsClearWarmReadCaches resets', async
rmSync(dir, { recursive: true, force: true })
})
test('vfs bareOsEvictLibBareBundlesFromManifest evicts only listed bundle paths', async (t) => {
const dir = testCorestoreDir('manifestevict')
const store = new Corestore(dir)
const sys = new Hyperdrive(store)
const personal = new Hyperdrive(store.namespace('me'))
await sys.ready()
await personal.ready()
await sys.put('/lib/bare/bundles/b4a.js', b4a.from('b4a'))
await sys.put('/lib/bare/bundles/safetyCatch.js', b4a.from('sc'))
const warmRef = { current: null }
const env = {
HOME: '/home/g',
PWD: '/',
PATH: '/bin',
BARE_OS_VFS_BIN_CACHE: '1',
BARE_OS_VFS_LIB_BARE_CACHE: '1'
}
const vfs = createVfs(sys, personal, env, null, {
warmReadCacheStatsRef: warmRef
})
await vfs.readFile('/lib/bare/bundles/b4a.js')
await vfs.readFile('/lib/bare/bundles/safetyCatch.js')
const hitsBefore = warmRef.current?.hits ?? 0
await vfs.readFile('/lib/bare/bundles/b4a.js')
t.ok((warmRef.current?.hits ?? 0) > hitsBefore)
const manifest = JSON.stringify({
version: 1,
entries: [
{ ctxKey: 'b4a', package: 'b4a', bundle: true },
{ ctxKey: 'xOther', package: 'x', bundle: false }
]
})
vfs.bareOsEvictLibBareBundlesFromManifest(b4a.from(manifest))
const missesAfterEvict = warmRef.current?.misses ?? 0
await vfs.readFile('/lib/bare/bundles/b4a.js')
t.ok(
(warmRef.current?.misses ?? 0) > missesAfterEvict,
'b4a should miss after selective evict'
)
const hitsSc = warmRef.current?.hits ?? 0
await vfs.readFile('/lib/bare/bundles/safetyCatch.js')
t.ok(
(warmRef.current?.hits ?? 0) > hitsSc,
'safetyCatch still served from warm cache'
)
await store.close()
rmSync(dir, { recursive: true, force: true })
})
test('blind relay / pairing / geo proc JSON stubbed without BARE_OS_PROC_BLIND_PEER_RELAY_HINTS', async (t) => {
const a = buildBareOsPearCorestoreHrpcProcJson('blind_relay_router', {})
t.is(a.exposed, false)
@@ -1079,11 +1130,78 @@ test('blind relay / pairing / geo proc JSON stubbed without BARE_OS_PROC_BLIND_P
t.is(b.exposed, false)
const c = buildBareOsHypercorePackHrpcLifecycleProcJson('relay_geo_hint', {})
t.is(c.exposed, false)
const on = buildBareOsPearCorestoreHrpcProcJson('blind_relay_router', {
BARE_OS_PROC_BLIND_PEER_RELAY_HINTS: '1',
BARE_OS_BLIND_RELAY_ROUTER_JSON: '{"lanes":1}'
})
const { buildBareOsBlindRelaySwarmRuntime } = await import(
'./lib/bare-os-proc-blind-peer-relay-gate.js'
)
const rt = {
swarm: buildBareOsBlindRelaySwarmRuntime(
{},
[{ id: 'a' }, { id: 'b' }]
)
}
const on = buildBareOsPearCorestoreHrpcProcJson(
'blind_relay_router',
{
BARE_OS_PROC_BLIND_PEER_RELAY_HINTS: '1',
BARE_OS_BLIND_RELAY_ROUTER_JSON: '{"lanes":1}'
},
rt
)
t.is(on.schema, 2)
t.is(on.exposed, true)
t.ok(on.router && typeof on.router === 'object')
t.is(on.swarm?.peerCount, 2)
t.is(on.swarm?.relayGeoTier, 'multi_peer')
const pair = buildBareOsPearInspectLoggerTlsProcJson(
'blind_pairing_sketch',
{ BARE_OS_PROC_BLIND_PEER_RELAY_HINTS: 'yes' },
rt
)
t.is(pair.schema, 2)
t.is(pair.swarm?.pairingSurfaceReady, true)
const geo = buildBareOsHypercorePackHrpcLifecycleProcJson(
'relay_geo_hint',
{ BARE_OS_PROC_BLIND_PEER_RELAY_HINTS: 'true' },
rt
)
t.is(geo.schema, 2)
t.ok(geo.regions == null)
t.is(geo.swarm?.relayGeoTier, 'multi_peer')
})
test('protomux_extensions proc JSON gated by BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY', async (t) => {
const off = buildBareOsProtomuxExtensionsProcJson({ env: {} })
t.is(off.exposed, false)
const on = buildBareOsProtomuxExtensionsProcJson({
env: { BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY: '1' },
registrySnapshot: { aliases: {}, schema: 1 },
ctxApiVersion: BARE_OS_CTX_API_VERSION
})
t.is(on.exposed, true)
t.ok(Array.isArray(on.extensionLogicalChannels))
})
test('buildBareOsReplicationLiveSketch reads hyperdrive core lengths', async (t) => {
const dir = testCorestoreDir('replive-sketch')
const store = new Corestore(dir)
const drive = new Hyperdrive(store)
const personal = new Hyperdrive(store.namespace('rls'))
await drive.ready()
await personal.ready()
const sk0 = buildBareOsReplicationLiveSketch(
{ drive, personalDrive: personal },
0
)
t.is(sk0.schema, 1)
t.is(sk0.stallHint, 'no_peers')
t.ok(typeof sk0.systemCoreLength === 'number')
const sk1 = buildBareOsReplicationLiveSketch(
{ drive, personalDrive: personal },
1
)
t.is(sk1.stallHint, 'ok')
await store.close()
rmSync(dir, { recursive: true, force: true })
})
test('protomux_rpc_pool_health proc uses schema 2 and backpressure correlation fields', async (t) => {
@@ -1135,6 +1253,8 @@ test('buildBareOsSyscallsProcJson exposes posixLike fd mapping', async (t) => {
t.ok(j.posixXsh.namesCsv.includes('poll'))
t.ok(j.posixXsh.namesCsv.includes('select'))
t.ok(j.posixXsh.namesCsv.includes('umask'))
t.ok(j.posixXsh.namesCsv.includes('readv'))
t.ok(j.posixXsh.namesCsv.includes('writev'))
t.ok(j.posixXsh.namesCsv.includes('socket'))
t.ok(j.posixXsh.namesCsv.includes('shutdown'))
const xsh = j.opsDetail.filter((r) => r.posixAlignment)
@@ -1512,6 +1632,7 @@ test('vfs /proc /sys read-only pseudo files; write rejected', async (t) => {
'bare_os_protomux_backpressure.json',
'bare_os_protomux_channel_alias_v2.json',
'bare_os_protomux_channels.json',
'bare_os_protomux_extensions.json',
'bare_os_protomux_rpc_pool_health.json',
'bare_os_protomux_wire.json',
'bare_os_provenance',
@@ -1973,6 +2094,33 @@ async function run(ctx, argv) {
rmSync(dir, { recursive: true, force: true })
})
test('execShellLine BARE_OS_SHELL_POSIX_MODE grouped list', async (t) => {
const dir = testCorestoreDir('shposixgroup')
const store = new Corestore(dir)
const drive = new Hyperdrive(store)
const personal = new Hyperdrive(store.namespace('spg'))
await drive.ready()
await personal.ready()
const echo = `
async function run(ctx, argv) {
ctx.console.log(argv.slice(1).join(' '))
}
`
await drive.put('/bin/echo', b4a.from(echo))
const ctx = testCtx(drive, personal)
const logs = []
ctx.console = {
log: (...a) => logs.push(a.join(' ')),
error: (...a) => logs.push(a.join(' '))
}
ctx.vfs.env.BARE_OS_SHELL_POSIX_MODE = '1'
await ctx.vfs.chdir('/home/user')
await execShellLine(ctx, '( echo hi )')
t.ok(logs.some((l) => l === 'hi'))
await store.close()
rmSync(dir, { recursive: true, force: true })
})
test('expandWord reads env', async (t) => {
t.is(expandWord('x${HOME}y', { HOME: '/h' }), 'x/hy')
})
@@ -5613,11 +5761,14 @@ test('worker_budget proc surface schema 2 exposes cpu and class map env', async
})
test('process table snapshot includes processGroups metadata', async (t) => {
const s = bareOsProcessTableSnapshot({})
const s = bareOsProcessTableSnapshot({
env: { BARE_OS_SHELL_PIPEFAIL: '1' }
})
t.ok(s.processGroups)
t.is(s.processGroups.schema, 1)
t.ok(String(s.processGroups.killpgAnalog).includes('killpg'))
t.is(s.schemaVersion, 5)
t.is(s.schemaVersion, 6)
t.ok(s.jobControlSemantics && s.jobControlSemantics.pipefail === true)
const booter = s.processes.find((p) => p && p.pid === 2)
t.ok(booter && booter.parentName === 'bare-os-kernel')
const shell = s.processes.find((p) => p && p.pid === 3)
+29 -1
View File
@@ -3,6 +3,7 @@
* Supports: BEGIN/END, /re/, line patterns, {}, print/printf, if/else, while, for(;;), for(x in a),
* next, exit, break, continue, ++/--, arrays, strings, regex ~ !~, builtins (length, substr, index,
* split, sprintf, sub, gsub, match, int, tolower, toupper, rand, srand), getline from stdin/files,
* optional fixed-width fields via FIELDWIDTHS when BARE_OS_AWK_FIELDWIDTHS is enabled,
* -F FS, NF, NR, FNR, $0..$n, OFS, ORS, RS, ARGC, ARGV, FILENAME, ENVIRON (read-only mirror).
* GNU-style empty fields: consecutive FS delimiters still advance $1..$NF where the grammar allows.
*/
@@ -130,7 +131,7 @@ function bareAwkLex(src, st) {
return { kind: 'OP', value: '==', line }
}
if ('+-*/%(){}[],;?:<>=!~^'.includes(c)) {
if ('+-*/%(){}[],;?:<>=!~^$'.includes(c)) {
st.i++
return { kind: 'OP', value: c, line }
}
@@ -718,6 +719,33 @@ class BareAwkRuntime {
}
splitFields() {
const cap = this.environ.BARE_OS_AWK_FIELDWIDTHS
if (cap === '1' || cap === 'true') {
const fw = String(
this.vars.FIELDWIDTHS != null ? this.vars.FIELDWIDTHS : ''
).trim()
if (fw) {
const nums = fw
.split(/\s+/)
.map((x) => Number.parseInt(x, 10))
.filter((n) => Number.isFinite(n) && n > 0)
if (nums.length) {
/** @type {string[]} */
const parts = []
let pos = 0
const line = this.$0
for (const w of nums) {
parts.push(line.slice(pos, pos + w))
pos += w
}
if (pos < line.length) parts.push(line.slice(pos))
this.fields = parts
this.NF = parts.length
this.vars.NF = this.NF
return
}
}
}
const fs = this.FS
let parts
if (fs === ' ') {
@@ -5,18 +5,18 @@
"synopsis": [
"mkfifo [OPTION]... [OPERAND]..."
],
"description": "FIFO special files are not implemented on Hyperdrive. The command reports failure.",
"description": "Creates an in-memory named channel for IPC under /run/bare-os/ipc/<name> when the booter exposes ctx.bareOsIpc. Paths must be under that prefix (e.g. /run/bare-os/ipc/demo). Not a kernel FIFO on Hyperdrive; use shell pipelines for stream composition between utilities.",
"options": [],
"keywords": [
"mkfifo",
"bare-os",
"coreutils"
],
"bareOsNotes": "Documented stub; no real pipes as kernel objects.",
"bareOsNotes": "Optional BARE_OS_IPC_NAMESPACE prefixes the logical channel key. See handbook ch.9 (FIFOs, simulated IPC).",
"examples": [
{
"caption": "stub",
"code": "# FIFOs not on Hyperdrive — use shell pipelines"
"caption": "create a named IPC channel",
"code": "mkfifo /run/bare-os/ipc/demo"
}
]
}
+1 -1
View File
@@ -54,7 +54,7 @@ const CONF = {
_PC_2_SYMLINKS: '1',
/** Comma-separated `ctx.bareOsSyscall` op names implemented in stock booter. */
BARE_OS_SYSCALL_OPS:
'accept,access,bind,chdir,chmod,connect,exists,fcntl,fdatasync,fsync,ftruncate,getcwd,kill,link,listen,lstat,mkdir,mount,pathconf,posixPoll,readFile,readdir,readlink,recv,rename,rmdir,select,send,shutdown,socket,stat,symlink,truncate,umask,umount,unlink,utimes,writeFile',
'accept,access,bind,chdir,chmod,connect,exists,fcntl,fdatasync,fsync,ftruncate,getcwd,getsockopt,kill,link,listen,lstat,mkdir,mount,pathconf,posixPoll,readFile,readdir,readlink,readv,recv,rename,rmdir,select,send,setsockopt,shutdown,socket,stat,symlink,truncate,umask,umount,unlink,utimes,writeFile,writev',
/** POSIX.1 XSH-style names documented in `/proc/bare_os/syscalls.json` opsDetail (socket family are syscall probes returning ENOSYS-shaped results). */
BARE_OS_POSIX_XSH_OPS:
'open,close,read,write,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,shutdown',
+43 -5
View File
@@ -2,7 +2,7 @@
* Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host spawn).
* Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation,
* 64 invocations per run. Exceeding limits is a fatal error (exit 125).
* Supports -0/--null, -n, -I repl (replace repl in utility argv; implies -n 1 unless -n given).
* Supports -0/--null, -n, -L (lines per invocation; mutually exclusive with -n), -I repl (replace repl in utility argv; implies -n 1 unless -n given).
* -P N runs up to N batches in parallel (each batch uses a shallow ctx clone so exitCode does not race).
* Max -P is min(requested, BARE_OS_XARGS_MAX_PROCS env, 32); default cap 8 when env unset.
*/
@@ -39,6 +39,8 @@ async function run(ctx, argv) {
/** @type {string | null} */
let repl = null
let nExplicit = false
/** @type {number | null} */
let linesPerInv = null
const envPCap = maxParallelFromEnv(ctx)
let pCap = 1
let i = 0
@@ -111,6 +113,23 @@ async function run(ctx, argv) {
i++
continue
}
if (a === '-L' || a === '--max-lines') {
const n = args[i + 1]
if (n == null || !/^\d+$/.test(n) || Number(n) < 1) {
ctx.console.error('xargs: -L requires a positive integer')
ctx.exitCode = 1
return
}
linesPerInv = Math.min(Number(n), MAX_PER_INVOCATION)
i += 2
continue
}
if (a.startsWith('-L') && a.length > 2 && /^\d+$/.test(a.slice(2))) {
const n = Number(a.slice(2))
linesPerInv = Math.min(n, MAX_PER_INVOCATION)
i++
continue
}
if (a === '-I' || a === '-i') {
repl = args[i + 1] != null ? String(args[i + 1]) : '{}'
i += 2
@@ -131,7 +150,7 @@ async function run(ctx, argv) {
ctx.console.error(
'xargs: Bare OS supports: -0/--null, -n N (max ' +
MAX_PER_INVOCATION +
' per run), -I repl, -P N (parallel batches, cap ' +
' per run), -L N (lines per invocation), -I repl, -P N (parallel batches, cap ' +
envPCap +
')'
)
@@ -139,6 +158,12 @@ async function run(ctx, argv) {
return
}
if (linesPerInv != null && nExplicit) {
ctx.console.error('xargs: -L cannot be combined with -n')
ctx.exitCode = 1
return
}
/** @type {string[]} */
let cmd = args.slice(i)
if (cmd.length === 0) cmd = ['echo']
@@ -154,7 +179,19 @@ async function run(ctx, argv) {
/** @type {string[]} */
let pieces
if (nullSep) {
if (linesPerInv != null) {
if (nullSep) {
pieces = text.split('\0').filter((s) => s.length > 0)
} else {
const raw = text.replace(/\r\n/g, '\n')
pieces =
raw.length === 0
? []
: raw.endsWith('\n')
? raw.slice(0, -1).split('\n')
: raw.split('\n')
}
} else if (nullSep) {
pieces = text.split('\0').filter((s) => s.length > 0)
} else {
pieces = text.trim() === '' ? [] : text.trim().split(/\s+/).filter(Boolean)
@@ -197,7 +234,8 @@ async function run(ctx, argv) {
/** @type {string[][]} */
const batches = []
for (let o = 0; o < pieces.length; o += maxBatch) {
const step = linesPerInv != null ? linesPerInv : maxBatch
for (let o = 0; o < pieces.length; o += step) {
if (batches.length >= MAX_INVOCATIONS) {
ctx.console.error(
'xargs: exceeded ' + MAX_INVOCATIONS + ' invocations (Bare OS limit)'
@@ -205,7 +243,7 @@ async function run(ctx, argv) {
ctx.exitCode = 125
return
}
batches.push(pieces.slice(o, o + maxBatch))
batches.push(pieces.slice(o, o + step))
}
if (pCap <= 1) {
@@ -13,12 +13,17 @@ const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor
/**
* @param {string} name
* @param {string[]} [libExtras] e.g. `['awk-engine.js']` before `awk.js` (matches `build.mjs` preamble).
*/
async function loadBin(name) {
async function loadBin(name, libExtras = []) {
const runtime = await readFile(
path.join(__dirname, '../lib/runtime.js'),
'utf8'
)
let pre = ''
for (const f of libExtras) {
pre += await readFile(path.join(__dirname, '../lib', f), 'utf8') + '\n'
}
const body = await readFile(
path.join(__dirname, `../src/${name}.js`),
'utf8'
@@ -26,7 +31,7 @@ async function loadBin(name) {
return new AsyncFunction(
'ctx',
'argv',
`${runtime}\n${body}\nif (typeof run === 'function') return await run(ctx, argv)\n`
`${runtime}\n${pre}${body}\nif (typeof run === 'function') return await run(ctx, argv)\n`
)
}
@@ -175,3 +180,44 @@ test('xargs invokes runBinCommand per token', async (t) => {
t.is(inv[0][1], 'a')
t.is(inv[1][1], 'b')
})
test('awk FIELDWIDTHS splits when BARE_OS_AWK_FIELDWIDTHS', async (t) => {
const run = await loadBin('awk', ['awk-engine.js'])
/** @type {string[]} */
const logs = []
const ctx = {
exitCode: 0,
shellStdin: 'abcde12\n',
b4a,
console: {
log: (/** @type {string} */ s) => logs.push(s),
error: () => {}
},
vfs: {
env: { BARE_OS_AWK_FIELDWIDTHS: '1' },
readFile: async () => null
}
}
await run(ctx, ['awk', '-v', 'FIELDWIDTHS=5 2', '{ print $2 }'])
t.is(ctx.exitCode, 0)
t.is(logs.join('\n'), '12')
})
test('xargs -L batches by input lines', async (t) => {
const run = await loadBin('xargs')
const inv = []
const ctx = {
exitCode: 0,
shellStdin: 'one\ntwo\nthree\n',
console: { log: () => {}, error: () => {} },
async runBinCommand(argv) {
inv.push([...argv])
ctx.exitCode = 0
}
}
await run(ctx, ['xargs', '-L', '2', 'echo'])
t.is(ctx.exitCode, 0)
t.is(inv.length, 2)
t.is(inv[0].slice(1).join(' '), 'one two')
t.is(inv[1].slice(1).join(' '), 'three')
})
@@ -4,7 +4,7 @@
*/
/** Semver for the documented POSIX-like surface (handbook ch.9 + environment appendix). */
export const BARE_OS_POSIX_PROFILE_VERSION = '1.0.4'
export const BARE_OS_POSIX_PROFILE_VERSION = '1.0.5'
/** Short identifier for telemetry and `/proc` mirrors. */
export const BARE_OS_POSIX_PROFILE_ID = 'bare-os-posix-like'
+29 -1
View File
@@ -92,6 +92,7 @@ function bareOsEmitRaw(ctx, chunk) {
* Supports: BEGIN/END, /re/, line patterns, {}, print/printf, if/else, while, for(;;), for(x in a),
* next, exit, break, continue, ++/--, arrays, strings, regex ~ !~, builtins (length, substr, index,
* split, sprintf, sub, gsub, match, int, tolower, toupper, rand, srand), getline from stdin/files,
* optional fixed-width fields via FIELDWIDTHS when BARE_OS_AWK_FIELDWIDTHS is enabled,
* -F FS, NF, NR, FNR, $0..$n, OFS, ORS, RS, ARGC, ARGV, FILENAME, ENVIRON (read-only mirror).
* GNU-style empty fields: consecutive FS delimiters still advance $1..$NF where the grammar allows.
*/
@@ -219,7 +220,7 @@ function bareAwkLex(src, st) {
return { kind: 'OP', value: '==', line }
}
if ('+-*/%(){}[],;?:<>=!~^'.includes(c)) {
if ('+-*/%(){}[],;?:<>=!~^$'.includes(c)) {
st.i++
return { kind: 'OP', value: c, line }
}
@@ -807,6 +808,33 @@ class BareAwkRuntime {
}
splitFields() {
const cap = this.environ.BARE_OS_AWK_FIELDWIDTHS
if (cap === '1' || cap === 'true') {
const fw = String(
this.vars.FIELDWIDTHS != null ? this.vars.FIELDWIDTHS : ''
).trim()
if (fw) {
const nums = fw
.split(/\s+/)
.map((x) => Number.parseInt(x, 10))
.filter((n) => Number.isFinite(n) && n > 0)
if (nums.length) {
/** @type {string[]} */
const parts = []
let pos = 0
const line = this.$0
for (const w of nums) {
parts.push(line.slice(pos, pos + w))
pos += w
}
if (pos < line.length) parts.push(line.slice(pos))
this.fields = parts
this.NF = parts.length
this.vars.NF = this.NF
return
}
}
}
const fs = this.FS
let parts
if (fs === ' ') {
+1 -1
View File
@@ -143,7 +143,7 @@ const CONF = {
_PC_2_SYMLINKS: '1',
/** Comma-separated `ctx.bareOsSyscall` op names implemented in stock booter. */
BARE_OS_SYSCALL_OPS:
'accept,access,bind,chdir,chmod,connect,exists,fcntl,fdatasync,fsync,ftruncate,getcwd,kill,link,listen,lstat,mkdir,mount,pathconf,posixPoll,readFile,readdir,readlink,recv,rename,rmdir,select,send,shutdown,socket,stat,symlink,truncate,umask,umount,unlink,utimes,writeFile',
'accept,access,bind,chdir,chmod,connect,exists,fcntl,fdatasync,fsync,ftruncate,getcwd,getsockopt,kill,link,listen,lstat,mkdir,mount,pathconf,posixPoll,readFile,readdir,readlink,readv,recv,rename,rmdir,select,send,setsockopt,shutdown,socket,stat,symlink,truncate,umask,umount,unlink,utimes,writeFile,writev',
/** POSIX.1 XSH-style names documented in `/proc/bare_os/syscalls.json` opsDetail (socket family are syscall probes returning ENOSYS-shaped results). */
BARE_OS_POSIX_XSH_OPS:
'open,close,read,write,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,shutdown',
+43 -5
View File
@@ -91,7 +91,7 @@ function bareOsEmitRaw(ctx, chunk) {
* Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host spawn).
* Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation,
* 64 invocations per run. Exceeding limits is a fatal error (exit 125).
* Supports -0/--null, -n, -I repl (replace repl in utility argv; implies -n 1 unless -n given).
* Supports -0/--null, -n, -L (lines per invocation; mutually exclusive with -n), -I repl (replace repl in utility argv; implies -n 1 unless -n given).
* -P N runs up to N batches in parallel (each batch uses a shallow ctx clone so exitCode does not race).
* Max -P is min(requested, BARE_OS_XARGS_MAX_PROCS env, 32); default cap 8 when env unset.
*/
@@ -128,6 +128,8 @@ async function run(ctx, argv) {
/** @type {string | null} */
let repl = null
let nExplicit = false
/** @type {number | null} */
let linesPerInv = null
const envPCap = maxParallelFromEnv(ctx)
let pCap = 1
let i = 0
@@ -200,6 +202,23 @@ async function run(ctx, argv) {
i++
continue
}
if (a === '-L' || a === '--max-lines') {
const n = args[i + 1]
if (n == null || !/^\d+$/.test(n) || Number(n) < 1) {
ctx.console.error('xargs: -L requires a positive integer')
ctx.exitCode = 1
return
}
linesPerInv = Math.min(Number(n), MAX_PER_INVOCATION)
i += 2
continue
}
if (a.startsWith('-L') && a.length > 2 && /^\d+$/.test(a.slice(2))) {
const n = Number(a.slice(2))
linesPerInv = Math.min(n, MAX_PER_INVOCATION)
i++
continue
}
if (a === '-I' || a === '-i') {
repl = args[i + 1] != null ? String(args[i + 1]) : '{}'
i += 2
@@ -220,7 +239,7 @@ async function run(ctx, argv) {
ctx.console.error(
'xargs: Bare OS supports: -0/--null, -n N (max ' +
MAX_PER_INVOCATION +
' per run), -I repl, -P N (parallel batches, cap ' +
' per run), -L N (lines per invocation), -I repl, -P N (parallel batches, cap ' +
envPCap +
')'
)
@@ -228,6 +247,12 @@ async function run(ctx, argv) {
return
}
if (linesPerInv != null && nExplicit) {
ctx.console.error('xargs: -L cannot be combined with -n')
ctx.exitCode = 1
return
}
/** @type {string[]} */
let cmd = args.slice(i)
if (cmd.length === 0) cmd = ['echo']
@@ -243,7 +268,19 @@ async function run(ctx, argv) {
/** @type {string[]} */
let pieces
if (nullSep) {
if (linesPerInv != null) {
if (nullSep) {
pieces = text.split('\0').filter((s) => s.length > 0)
} else {
const raw = text.replace(/\r\n/g, '\n')
pieces =
raw.length === 0
? []
: raw.endsWith('\n')
? raw.slice(0, -1).split('\n')
: raw.split('\n')
}
} else if (nullSep) {
pieces = text.split('\0').filter((s) => s.length > 0)
} else {
pieces = text.trim() === '' ? [] : text.trim().split(/\s+/).filter(Boolean)
@@ -286,7 +323,8 @@ async function run(ctx, argv) {
/** @type {string[][]} */
const batches = []
for (let o = 0; o < pieces.length; o += maxBatch) {
const step = linesPerInv != null ? linesPerInv : maxBatch
for (let o = 0; o < pieces.length; o += step) {
if (batches.length >= MAX_INVOCATIONS) {
ctx.console.error(
'xargs: exceeded ' + MAX_INVOCATIONS + ' invocations (Bare OS limit)'
@@ -294,7 +332,7 @@ async function run(ctx, argv) {
ctx.exitCode = 125
return
}
batches.push(pieces.slice(o, o + maxBatch))
batches.push(pieces.slice(o, o + step))
}
if (pCap <= 1) {
@@ -1,9 +1,9 @@
{
"schemaVersion": 5,
"ctxApiVersion": "1.38.0",
"ctxApiVersion": "1.40.0",
"posixProfile": {
"id": "bare-os-posix-like",
"version": "1.0.4"
"version": "1.0.5"
},
"ops": ["readFile", "writeFile", "socket"],
"opsDetail": [
@@ -29,7 +29,7 @@
"posixXsh": {
"schema": 1,
"note": "POSIX.1 XSH-style names; socket family are ctx.bareOsSyscall ops returning ENOSYS-shaped results.",
"namesCsv": "open,close,read,write,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,shutdown"
"namesCsv": "open,close,read,write,readv,writev,getsockopt,setsockopt,lseek,pipe,dup,dup2,fcntl,poll,select,umask,socket,bind,listen,accept,connect,send,recv,shutdown"
},
"errnoHints": {
"ENOENT": 2,
@@ -42,7 +42,7 @@
"stdio": [0, 1, 2],
"register": "ctx.bareOsRegisterLogicalFd",
"processTablePath": "/proc/bare_os/process_table.json",
"processTableSchema": 5
"processTableSchema": 6
},
"signalModel": {
"schema": 1,
+55 -1
View File
@@ -64,6 +64,7 @@ async function invokeCtxBootHooks(ctx, ev) {
* BARE_OS_SELFTEST_FORMAT=tap: TAP-style lines on stderr for CI parsers; **junit**: single XML `<testsuite>` line on stderr.
* BARE_OS_KERNEL_STARTUP_CLASS: `critical` | `system` | `interactive` | `deferred` (default **interactive**); exposed as **`ctx.bareOsKernelStartupClass`** for extensions/initd.
* BARE_OS_BOOT_BUDGET_MS_COLD: optional cold-boot wall-time warning threshold (ms) after **`bareOsPublishBootReady`**.
* BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB: optional wall-time budget (ms) for booter **`ctx.bare`** drive merge + host resolve (**`BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS`**, set by the stock booter); guest logs and **`boot-perf.json`** when exceeded.
* BARE_OS_BOOT_CAPABILITY_CONTRACT_DEBUG=1: log capability-contract merge diagnostics (strict builds).
* BARE_OS_BOOT_EXT_RESOLUTION_TRACE=1 with **BARE_OS_BOOT_POLICY_STRICT**: write **`/run/bare-os/kernel-ext-resolution.json`** (extension load order / cycle ids).
* BARE_OS_BOOT_RC_RESOLUTION_TRACE=1 with **BARE_OS_BOOT_POLICY_STRICT**: write **`/run/bare-os/rc-d-resolution.json`** and **`/run/bare-os/kernel-d-resolution.json`** (lexicographic execution order after filters).
@@ -3040,13 +3041,29 @@ async function maybeWriteBootPerfJson(ctx, bootT0, stageLog) {
10
)
const budget = Number.isFinite(budgetRaw) && budgetRaw > 0 ? budgetRaw : null
const stdlibWallRaw = Number.parseInt(
String(ctx.env?.BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS || ''),
10
)
const stdlibWall =
Number.isFinite(stdlibWallRaw) && stdlibWallRaw >= 0 ? stdlibWallRaw : null
const stdlibBudgetRaw = Number.parseInt(
String(ctx.env?.BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB || ''),
10
)
const stdlibBudget =
Number.isFinite(stdlibBudgetRaw) && stdlibBudgetRaw > 0
? stdlibBudgetRaw
: null
const stages =
Array.isArray(ctx.bareOsBootStageTimings) && ctx.bareOsBootStageTimings.length
? ctx.bareOsBootStageTimings
: undefined
let schema = stages ? 2 : 1
if (stdlibWall != null || stdlibBudget != null) schema = Math.max(schema, 3)
const row =
JSON.stringify({
schema: stages ? 2 : 1,
schema,
coldWallMs: wall,
bootBudgetMsCold: budget,
withinBudget: budget == null ? null : wall <= budget,
@@ -3054,6 +3071,18 @@ async function maybeWriteBootPerfJson(ctx, bootT0, stageLog) {
budget != null && wall > budget
? `cold boot ${wall}ms exceeded BARE_OS_BOOT_BUDGET_MS_COLD ${budget}ms`
: null,
bareStdlibResolutionWallMs: stdlibWall,
bareStdlibBudgetMs: stdlibBudget,
bareStdlibWithinBudget:
stdlibBudget == null || stdlibWall == null
? null
: stdlibWall <= stdlibBudget,
bareStdlibBudgetWarning:
stdlibBudget != null &&
stdlibWall != null &&
stdlibWall > stdlibBudget
? `bare stdlib resolution ${stdlibWall}ms exceeded BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB ${stdlibBudget}ms`
: null,
stageCount: stageLog.length,
stages,
completedAtMs: Date.now()
@@ -3390,6 +3419,31 @@ async function start(ctx) {
}
}
}
{
const sb = Number.parseInt(
String(ctx.env?.BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB || ''),
10
)
if (Number.isFinite(sb) && sb > 0) {
const sw = Number.parseInt(
String(ctx.env?.BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS || ''),
10
)
if (Number.isFinite(sw) && sw > sb) {
bootStructuredLog(
ctx,
'error',
'bootBudgetBareStdlibExceeded',
`[boot] bare stdlib resolution ${sw}ms exceeds BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB=${sb}ms`
)
if (ctx.env) {
ctx.env.BARE_OS_BOOT_BUDGET_STDLIB_EXCEEDED = '1'
ctx.env.BARE_OS_BOOT_BUDGET_STDLIB_WALL_MS = String(sw)
ctx.env.BARE_OS_BOOT_BUDGET_STDLIB_LIMIT_MS = String(sb)
}
}
}
}
while (true) {
const line = await readLine('')
if (line == null) break
File diff suppressed because one or more lines are too long
@@ -2,9 +2,9 @@
"version": 1,
"bundles": [
{
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
"path": "/lib/bare/bundles/safetyCatch.js",
"keys": [
"hypercoreIdEncoding"
"safetyCatch"
]
},
{
@@ -14,9 +14,9 @@
]
},
{
"path": "/lib/bare/bundles/safetyCatch.js",
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
"keys": [
"safetyCatch"
"hypercoreIdEncoding"
]
},
{
@@ -25,12 +25,6 @@
"compactEncoding"
]
},
{
"path": "/lib/bare/bundles/protomux.js",
"keys": [
"protomux"
]
},
{
"path": "/lib/bare/bundles/bareUrl.js",
"keys": [
@@ -38,9 +32,9 @@
]
},
{
"path": "/lib/bare/bundles/bareEncoding.js",
"path": "/lib/bare/bundles/protomux.js",
"keys": [
"bareEncoding"
"protomux"
]
},
{
@@ -55,12 +49,30 @@
"barePath"
]
},
{
"path": "/lib/bare/bundles/bareEncoding.js",
"keys": [
"bareEncoding"
]
},
{
"path": "/lib/bare/bundles/bareAbort.js",
"keys": [
"bareAbort"
]
},
{
"path": "/lib/bare/bundles/bareReadline.js",
"keys": [
"bareReadline"
]
},
{
"path": "/lib/bare/bundles/bareCrypto.js",
"keys": [
"bareCrypto"
]
},
{
"path": "/lib/bare/bundles/bareAbortController.js",
"keys": [
@@ -73,36 +85,18 @@
"bareAnsiEscapes"
]
},
{
"path": "/lib/bare/bundles/bareReadline.js",
"keys": [
"bareReadline"
]
},
{
"path": "/lib/bare/bundles/bareAddonResolve.js",
"keys": [
"bareAddonResolve"
]
},
{
"path": "/lib/bare/bundles/bareCrypto.js",
"keys": [
"bareCrypto"
]
},
{
"path": "/lib/bare/bundles/bareAsyncHooks.js",
"keys": [
"bareAsyncHooks"
]
},
{
"path": "/lib/bare/bundles/bareAssert.js",
"keys": [
"bareAssert"
]
},
{
"path": "/lib/bare/bundles/bareAppKit.js",
"keys": [
@@ -116,15 +110,15 @@
]
},
{
"path": "/lib/bare/bundles/bareApk.js",
"path": "/lib/bare/bundles/bareAssert.js",
"keys": [
"bareApk"
"bareAssert"
]
},
{
"path": "/lib/bare/bundles/bareBmp.js",
"path": "/lib/bare/bundles/bareApk.js",
"keys": [
"bareBmp"
"bareApk"
]
},
{
@@ -134,9 +128,9 @@
]
},
{
"path": "/lib/bare/bundles/bareBundle.js",
"path": "/lib/bare/bundles/bareBmp.js",
"keys": [
"bareBundle"
"bareBmp"
]
},
{
@@ -145,6 +139,12 @@
"bareBundleCompile"
]
},
{
"path": "/lib/bare/bundles/bareBundle.js",
"keys": [
"bareBundle"
]
},
{
"path": "/lib/bare/bundles/bareBuffer.js",
"keys": [
@@ -163,48 +163,48 @@
"bareBundleEvaluate"
]
},
{
"path": "/lib/bare/bundles/bareBoot.js",
"keys": [
"bareBoot"
]
},
{
"path": "/lib/bare/bundles/bareConsole.js",
"keys": [
"bareConsole"
]
},
{
"path": "/lib/bare/bundles/bareBoot.js",
"keys": [
"bareBoot"
]
},
{
"path": "/lib/bare/bundles/bareBundleId.js",
"keys": [
"bareBundleId"
]
},
{
"path": "/lib/bare/bundles/bareDebugLog.js",
"keys": [
"bareDebugLog"
]
},
{
"path": "/lib/bare/bundles/bareDaemon.js",
"keys": [
"bareDaemon"
]
},
{
"path": "/lib/bare/bundles/bareChannel.js",
"keys": [
"bareChannel"
]
},
{
"path": "/lib/bare/bundles/bareDebugLog.js",
"keys": [
"bareDebugLog"
]
},
{
"path": "/lib/bare/bundles/bareDelta.js",
"keys": [
"bareDelta"
]
},
{
"path": "/lib/bare/bundles/bareDaemon.js",
"keys": [
"bareDaemon"
]
},
{
"path": "/lib/bare/bundles/bareDiagnosticsChannel.js",
"keys": [
@@ -223,12 +223,6 @@
"bareEnv"
]
},
{
"path": "/lib/bare/bundles/bareExif.js",
"keys": [
"bareExif"
]
},
{
"path": "/lib/bare/bundles/bareCov.js",
"keys": [
@@ -236,9 +230,9 @@
]
},
{
"path": "/lib/bare/bundles/bareFfmpeg.js",
"path": "/lib/bare/bundles/bareExif.js",
"keys": [
"bareFfmpeg"
"bareExif"
]
},
{
@@ -247,30 +241,30 @@
"bareDgram"
]
},
{
"path": "/lib/bare/bundles/bareFfmpeg.js",
"keys": [
"bareFfmpeg"
]
},
{
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
"keys": [
"bareFfmpegEncodings"
]
},
{
"path": "/lib/bare/bundles/bareFormat.js",
"keys": [
"bareFormat"
]
},
{
"path": "/lib/bare/bundles/bareGif.js",
"keys": [
"bareGif"
]
},
{
"path": "/lib/bare/bundles/bareFileLogger.js",
"keys": [
"bareFileLogger"
]
},
{
"path": "/lib/bare/bundles/bareFormat.js",
"keys": [
"bareFormat"
]
},
{
"path": "/lib/bare/bundles/bareFormData.js",
"keys": [
@@ -278,9 +272,9 @@
]
},
{
"path": "/lib/bare/bundles/bareHrtime.js",
"path": "/lib/bare/bundles/bareGif.js",
"keys": [
"bareHrtime"
"bareGif"
]
},
{
@@ -290,9 +284,9 @@
]
},
{
"path": "/lib/bare/bundles/bareFs.js",
"path": "/lib/bare/bundles/bareHrtime.js",
"keys": [
"bareFs"
"bareHrtime"
]
},
{
@@ -307,6 +301,18 @@
"bareHttpParser"
]
},
{
"path": "/lib/bare/bundles/bareFs.js",
"keys": [
"bareFs"
]
},
{
"path": "/lib/bare/bundles/bareIco.js",
"keys": [
"bareIco"
]
},
{
"path": "/lib/bare/bundles/bareImageResample.js",
"keys": [
@@ -319,24 +325,12 @@
"bareInspect"
]
},
{
"path": "/lib/bare/bundles/bareIco.js",
"keys": [
"bareIco"
]
},
{
"path": "/lib/bare/bundles/bareHttp1.js",
"keys": [
"bareHttp1"
]
},
{
"path": "/lib/bare/bundles/bareJpeg.js",
"keys": [
"bareJpeg"
]
},
{
"path": "/lib/bare/bundles/bareHttps.js",
"keys": [
@@ -344,9 +338,9 @@
]
},
{
"path": "/lib/bare/bundles/bareIpc.js",
"path": "/lib/bare/bundles/bareJpeg.js",
"keys": [
"bareIpc"
"bareJpeg"
]
},
{
@@ -356,15 +350,9 @@
]
},
{
"path": "/lib/bare/bundles/bareInspector.js",
"path": "/lib/bare/bundles/bareIpc.js",
"keys": [
"bareInspector"
]
},
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
"bareIpc"
]
},
{
@@ -374,9 +362,9 @@
]
},
{
"path": "/lib/bare/bundles/bareMake.js",
"path": "/lib/bare/bundles/bareInspector.js",
"keys": [
"bareMake"
"bareInspector"
]
},
{
@@ -385,24 +373,36 @@
"bareLink"
]
},
{
"path": "/lib/bare/bundles/bareLogger.js",
"keys": [
"bareLogger"
]
},
{
"path": "/lib/bare/bundles/bareMake.js",
"keys": [
"bareMake"
]
},
{
"path": "/lib/bare/bundles/bareModuleLexer.js",
"keys": [
"bareModuleLexer"
]
},
{
"path": "/lib/bare/bundles/bareModuleResolve.js",
"keys": [
"bareModuleResolve"
]
},
{
"path": "/lib/bare/bundles/bareModule.js",
"keys": [
"bareModule"
]
},
{
"path": "/lib/bare/bundles/bareModuleResolve.js",
"keys": [
"bareModuleResolve"
]
},
{
"path": "/lib/bare/bundles/bareModuleTraverse.js",
"keys": [
@@ -421,36 +421,36 @@
"bareNative"
]
},
{
"path": "/lib/bare/bundles/bareMedia.js",
"keys": [
"bareMedia"
]
},
{
"path": "/lib/bare/bundles/bareNodeFetch.js",
"keys": [
"bareNodeFetch"
]
},
{
"path": "/lib/bare/bundles/bareOpen.js",
"keys": [
"bareOpen"
]
},
{
"path": "/lib/bare/bundles/bareNet.js",
"keys": [
"bareNet"
]
},
{
"path": "/lib/bare/bundles/bareOpen.js",
"keys": [
"bareOpen"
]
},
{
"path": "/lib/bare/bundles/bareOs.js",
"keys": [
"bareOs"
]
},
{
"path": "/lib/bare/bundles/bareMedia.js",
"keys": [
"bareMedia"
]
},
{
"path": "/lib/bare/bundles/barePerformance.js",
"keys": [
@@ -458,9 +458,9 @@
]
},
{
"path": "/lib/bare/bundles/barePack.js",
"path": "/lib/bare/bundles/barePackDrive.js",
"keys": [
"barePack"
"barePackDrive"
]
},
{
@@ -470,9 +470,9 @@
]
},
{
"path": "/lib/bare/bundles/barePackDrive.js",
"path": "/lib/bare/bundles/barePack.js",
"keys": [
"barePackDrive"
"barePack"
]
},
{
@@ -487,48 +487,48 @@
"bareNodeRuntime"
]
},
{
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareDev"
]
},
{
"path": "/lib/bare/bundles/barePunycode.js",
"keys": [
"barePunycode"
]
},
{
"path": "/lib/bare/bundles/barePrebuild.js",
"keys": [
"barePrebuild"
]
},
{
"path": "/lib/bare/bundles/bareQuerystring.js",
"keys": [
"bareQuerystring"
]
},
{
"path": "/lib/bare/bundles/bareDev.js",
"keys": [
"bareDev"
]
},
{
"path": "/lib/bare/bundles/barePrebuild.js",
"keys": [
"barePrebuild"
]
},
{
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
"keys": [
"bareQueueMicrotask"
]
},
{
"path": "/lib/bare/bundles/bareProcess.js",
"keys": [
"bareProcess"
]
},
{
"path": "/lib/bare/bundles/bareRealm.js",
"keys": [
"bareRealm"
]
},
{
"path": "/lib/bare/bundles/bareProcess.js",
"keys": [
"bareProcess"
]
},
{
"path": "/lib/bare/bundles/barePromClient.js",
"keys": [
@@ -541,6 +541,12 @@
"bareRuntime"
]
},
{
"path": "/lib/bare/bundles/bareSemver.js",
"keys": [
"bareSemver"
]
},
{
"path": "/lib/bare/bundles/bareSdl.js",
"keys": [
@@ -553,66 +559,36 @@
"bareRpc"
]
},
{
"path": "/lib/bare/bundles/bareSemver.js",
"keys": [
"bareSemver"
]
},
{
"path": "/lib/bare/bundles/bareRepl.js",
"keys": [
"bareRepl"
]
},
{
"path": "/lib/bare/bundles/bareSignals.js",
"keys": [
"bareSignals"
]
},
{
"path": "/lib/bare/bundles/bareRun.js",
"keys": [
"bareRun"
]
},
{
"path": "/lib/bare/bundles/bareSidecar.js",
"keys": [
"bareSidecar"
]
},
{
"path": "/lib/bare/bundles/bareRun.js",
"keys": [
"bareRun"
]
},
{
"path": "/lib/bare/bundles/bareSignals.js",
"keys": [
"bareSignals"
]
},
{
"path": "/lib/bare/bundles/bareStorage.js",
"keys": [
"bareStorage"
]
},
{
"path": "/lib/bare/bundles/bareStream.js",
"keys": [
"bareStream"
]
},
{
"path": "/lib/bare/bundles/bareStdio.js",
"keys": [
"bareStdio"
]
},
{
"path": "/lib/bare/bundles/bareSvg.js",
"keys": [
"bareSvg"
]
},
{
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareSystemLogger"
]
},
{
"path": "/lib/bare/bundles/bareStringDecoder.js",
"keys": [
@@ -620,15 +596,21 @@
]
},
{
"path": "/lib/bare/bundles/bareSubprocess.js",
"path": "/lib/bare/bundles/bareStdio.js",
"keys": [
"bareSubprocess"
"bareStdio"
]
},
{
"path": "/lib/bare/bundles/bareTap.js",
"path": "/lib/bare/bundles/bareStream.js",
"keys": [
"bareTap"
"bareStream"
]
},
{
"path": "/lib/bare/bundles/bareSvg.js",
"keys": [
"bareSvg"
]
},
{
@@ -637,24 +619,48 @@
"bareStructuredClone"
]
},
{
"path": "/lib/bare/bundles/bareTcp.js",
"keys": [
"bareTcp"
]
},
{
"path": "/lib/bare/bundles/bareTiff.js",
"keys": [
"bareTiff"
]
},
{
"path": "/lib/bare/bundles/bareSubprocess.js",
"keys": [
"bareSubprocess"
]
},
{
"path": "/lib/bare/bundles/bareSystemLogger.js",
"keys": [
"bareSystemLogger"
]
},
{
"path": "/lib/bare/bundles/bareTap.js",
"keys": [
"bareTap"
]
},
{
"path": "/lib/bare/bundles/bareThread.js",
"keys": [
"bareThread"
]
},
{
"path": "/lib/bare/bundles/bareTcp.js",
"keys": [
"bareTcp"
]
},
{
"path": "/lib/bare/bundles/bareTpl.js",
"keys": [
"bareTpl"
]
},
{
"path": "/lib/bare/bundles/bareTimers.js",
"keys": [
@@ -667,24 +673,6 @@
"bareType"
]
},
{
"path": "/lib/bare/bundles/bareTpl.js",
"keys": [
"bareTpl"
]
},
{
"path": "/lib/bare/bundles/bareTty.js",
"keys": [
"bareTty"
]
},
{
"path": "/lib/bare/bundles/bareTls.js",
"keys": [
"bareTls"
]
},
{
"path": "/lib/bare/bundles/bareUiKit.js",
"keys": [
@@ -698,15 +686,21 @@
]
},
{
"path": "/lib/bare/bundles/bareV8.js",
"path": "/lib/bare/bundles/bareTls.js",
"keys": [
"bareV8"
"bareTls"
]
},
{
"path": "/lib/bare/bundles/bareVm.js",
"path": "/lib/bare/bundles/bareTty.js",
"keys": [
"bareVm"
"bareTty"
]
},
{
"path": "/lib/bare/bundles/bareV8.js",
"keys": [
"bareV8"
]
},
{
@@ -722,15 +716,9 @@
]
},
{
"path": "/lib/bare/bundles/bareWebKit.js",
"path": "/lib/bare/bundles/bareVm.js",
"keys": [
"bareWebKit"
]
},
{
"path": "/lib/bare/bundles/bareWebp.js",
"keys": [
"bareWebp"
"bareVm"
]
},
{
@@ -740,9 +728,9 @@
]
},
{
"path": "/lib/bare/bundles/bareWebKitGtk.js",
"path": "/lib/bare/bundles/bareWebKit.js",
"keys": [
"bareWebKitGtk"
"bareWebKit"
]
},
{
@@ -751,6 +739,18 @@
"bareWhich"
]
},
{
"path": "/lib/bare/bundles/bareWebp.js",
"keys": [
"bareWebp"
]
},
{
"path": "/lib/bare/bundles/bareWebKitGtk.js",
"keys": [
"bareWebKitGtk"
]
},
{
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
"keys": [
@@ -769,6 +769,12 @@
"bareXdiff"
]
},
{
"path": "/lib/bare/bundles/bareZlib.js",
"keys": [
"bareZlib"
]
},
{
"path": "/lib/bare/bundles/bareWs.js",
"keys": [
@@ -781,12 +787,6 @@
"bareWorker"
]
},
{
"path": "/lib/bare/bundles/bareZlib.js",
"keys": [
"bareZlib"
]
},
{
"path": "/lib/bare/bundles/bareZmq.js",
"keys": [
@@ -1595,8 +1595,8 @@
],
"bundleProvenance": {
"schemaVersion": 1,
"generatedAt": "2026-04-05T03:36:27.100Z",
"gitCommit": "13a06ea3e93e38088f3f893f2c4ba0c9e595808f",
"generatedAt": "2026-04-05T04:01:55.827Z",
"gitCommit": "16ac71815f00d2c56ac82a964633010e78bd0cdc",
"nodeVersion": "v22.22.0",
"bundleTier": "all",
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
@@ -1,6 +1,6 @@
{
"schema": 1,
"atMs": 1775360186009,
"atMs": 1775361714981,
"commands": [
"arch",
"awk",
@@ -34,6 +34,7 @@
* BARE_OS_SELFTEST_FORMAT=tap: TAP-style lines on stderr for CI parsers; **junit**: single XML `<testsuite>` line on stderr.
* BARE_OS_KERNEL_STARTUP_CLASS: `critical` | `system` | `interactive` | `deferred` (default **interactive**); exposed as **`ctx.bareOsKernelStartupClass`** for extensions/initd.
* BARE_OS_BOOT_BUDGET_MS_COLD: optional cold-boot wall-time warning threshold (ms) after **`bareOsPublishBootReady`**.
* BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB: optional wall-time budget (ms) for booter **`ctx.bare`** drive merge + host resolve (**`BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS`**, set by the stock booter); guest logs and **`boot-perf.json`** when exceeded.
* BARE_OS_BOOT_CAPABILITY_CONTRACT_DEBUG=1: log capability-contract merge diagnostics (strict builds).
* BARE_OS_BOOT_EXT_RESOLUTION_TRACE=1 with **BARE_OS_BOOT_POLICY_STRICT**: write **`/run/bare-os/kernel-ext-resolution.json`** (extension load order / cycle ids).
* BARE_OS_BOOT_RC_RESOLUTION_TRACE=1 with **BARE_OS_BOOT_POLICY_STRICT**: write **`/run/bare-os/rc-d-resolution.json`** and **`/run/bare-os/kernel-d-resolution.json`** (lexicographic execution order after filters).
@@ -3010,13 +3011,29 @@ async function maybeWriteBootPerfJson(ctx, bootT0, stageLog) {
10
)
const budget = Number.isFinite(budgetRaw) && budgetRaw > 0 ? budgetRaw : null
const stdlibWallRaw = Number.parseInt(
String(ctx.env?.BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS || ''),
10
)
const stdlibWall =
Number.isFinite(stdlibWallRaw) && stdlibWallRaw >= 0 ? stdlibWallRaw : null
const stdlibBudgetRaw = Number.parseInt(
String(ctx.env?.BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB || ''),
10
)
const stdlibBudget =
Number.isFinite(stdlibBudgetRaw) && stdlibBudgetRaw > 0
? stdlibBudgetRaw
: null
const stages =
Array.isArray(ctx.bareOsBootStageTimings) && ctx.bareOsBootStageTimings.length
? ctx.bareOsBootStageTimings
: undefined
let schema = stages ? 2 : 1
if (stdlibWall != null || stdlibBudget != null) schema = Math.max(schema, 3)
const row =
JSON.stringify({
schema: stages ? 2 : 1,
schema,
coldWallMs: wall,
bootBudgetMsCold: budget,
withinBudget: budget == null ? null : wall <= budget,
@@ -3024,6 +3041,18 @@ async function maybeWriteBootPerfJson(ctx, bootT0, stageLog) {
budget != null && wall > budget
? `cold boot ${wall}ms exceeded BARE_OS_BOOT_BUDGET_MS_COLD ${budget}ms`
: null,
bareStdlibResolutionWallMs: stdlibWall,
bareStdlibBudgetMs: stdlibBudget,
bareStdlibWithinBudget:
stdlibBudget == null || stdlibWall == null
? null
: stdlibWall <= stdlibBudget,
bareStdlibBudgetWarning:
stdlibBudget != null &&
stdlibWall != null &&
stdlibWall > stdlibBudget
? `bare stdlib resolution ${stdlibWall}ms exceeded BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB ${stdlibBudget}ms`
: null,
stageCount: stageLog.length,
stages,
completedAtMs: Date.now()
@@ -3360,6 +3389,31 @@ async function start(ctx) {
}
}
}
{
const sb = Number.parseInt(
String(ctx.env?.BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB || ''),
10
)
if (Number.isFinite(sb) && sb > 0) {
const sw = Number.parseInt(
String(ctx.env?.BARE_OS_BOOT_BARE_STDLIB_RESOLUTION_MS || ''),
10
)
if (Number.isFinite(sw) && sw > sb) {
bootStructuredLog(
ctx,
'error',
'bootBudgetBareStdlibExceeded',
`[boot] bare stdlib resolution ${sw}ms exceeds BARE_OS_BOOT_BUDGET_MS_BARE_STDLIB=${sb}ms`
)
if (ctx.env) {
ctx.env.BARE_OS_BOOT_BUDGET_STDLIB_EXCEEDED = '1'
ctx.env.BARE_OS_BOOT_BUDGET_STDLIB_WALL_MS = String(sw)
ctx.env.BARE_OS_BOOT_BUDGET_STDLIB_LIMIT_MS = String(sb)
}
}
}
}
while (true) {
const line = await readLine('')
if (line == null) break
File diff suppressed because one or more lines are too long