feat(shell): job-aware kill, disown, jobs/set flags, fallback REPL history
- Document interactive shell vs /bin/sh in bare-os-shell man, handbook §9, kill(1), and shell-completion guide - Resolve kill %n and %% to synthetic PIDs via shellBackgroundJobs - Add disown builtin; jobs -p (pgid-only) and -l (pid column); set -o/+o to print errexit/nounset/pipefail/noglob - Expand completion-engine fallback flags for common utilities - Persist lines to /.bare/repl_history_<USER> when BARE_OS_REPL_HISTORY=1 and Fish REPL is off (repl-session + cli-readline) - Tests: kill job specs, set -o output, jobs -p
This commit is contained in:
@@ -4,6 +4,11 @@
|
||||
*/
|
||||
|
||||
import { createInterface as bareReadlineCreateInterface } from 'bare-readline'
|
||||
import {
|
||||
dedupeConsecutiveHistory,
|
||||
formatHistoryFile,
|
||||
parseHistoryFile
|
||||
} from './fish-readline.js'
|
||||
|
||||
/**
|
||||
* Strip C0 controls; apply BS (0x08) and DEL (0x7F) for raw SSH line fallback.
|
||||
@@ -28,7 +33,7 @@ export function sanitizeInteractiveShellLine(s) {
|
||||
* Caller should call **`close()`** when the session ends to detach input listeners.
|
||||
*
|
||||
* bare-readline treats **`prompt: ''` as falsy** and falls back to `'> '`, which flashes
|
||||
* after each `new Readline` (e.g. SSH recycle). Use a non-empty placeholder or pass
|
||||
* after each `new Readline` (e.g. SSH recycle). Use a non-empty prompt string or pass
|
||||
* **`initialPrompt`** so the constructor’s first `prompt()` matches the real PS1.
|
||||
*
|
||||
* @param {import('stream').Readable} stdin
|
||||
@@ -162,3 +167,73 @@ export function looksLikeInteractiveStdin(stdin) {
|
||||
typeof stdin.resume === 'function'
|
||||
)
|
||||
}
|
||||
|
||||
const REPL_HISTORY_CAP = 1000
|
||||
|
||||
/**
|
||||
* Same path as Fish REPL (`fish-readline.js`) so fallback and Fish share one file.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
*/
|
||||
function bareReplHistoryDrivePath(ctx) {
|
||||
const u = String(
|
||||
ctx?.vfs?.env?.USER ?? (ctx.env && ctx.env.USER) ?? 'guest'
|
||||
).replace(/[^a-zA-Z0-9._-]/g, '_')
|
||||
return `/.bare/repl_history_${u}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Append one line to `/.bare/repl_history_<USER>` when Fish-style REPL is off.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string} line
|
||||
*/
|
||||
async function appendBareReplHistory(ctx, line) {
|
||||
const trimmed = String(line).trim()
|
||||
if (!trimmed) return
|
||||
const personalDrive = ctx.personalDrive
|
||||
const b4a = ctx.b4a
|
||||
if (
|
||||
!personalDrive ||
|
||||
typeof personalDrive.get !== 'function' ||
|
||||
typeof personalDrive.put !== 'function' ||
|
||||
!b4a ||
|
||||
typeof b4a.from !== 'function'
|
||||
) {
|
||||
return
|
||||
}
|
||||
const historyPath = bareReplHistoryDrivePath(ctx)
|
||||
/** @type {Array<{ timestamp: number, command: string }>} */
|
||||
let history = []
|
||||
try {
|
||||
const buf = await personalDrive.get(historyPath)
|
||||
if (buf) history = dedupeConsecutiveHistory(parseHistoryFile(b4a.toString(buf)))
|
||||
} catch {
|
||||
history = []
|
||||
}
|
||||
history = history.filter((e) => e.command !== trimmed)
|
||||
history.push({ timestamp: Date.now(), command: trimmed })
|
||||
while (history.length > REPL_HISTORY_CAP) history.shift()
|
||||
await personalDrive.put(historyPath, b4a.from(formatHistoryFile(history)))
|
||||
}
|
||||
|
||||
/**
|
||||
* When **`BARE_OS_FISH=0`** or the TTY cannot use Fish, optionally persist lines to the
|
||||
* same history file Fish uses (**`BARE_OS_REPL_HISTORY=1`**). Does not add arrow-key
|
||||
* recall (use Fish REPL for full editing).
|
||||
*
|
||||
* @param {(prompt: string) => Promise<string | null>} innerReadLine
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @returns {(prompt: string) => Promise<string | null>}
|
||||
*/
|
||||
export function wrapReadLineWithReplHistoryPersist(innerReadLine, ctx) {
|
||||
return async function readLine(prompt) {
|
||||
const ln = await innerReadLine(prompt)
|
||||
if (ln != null && String(ln).trim()) {
|
||||
try {
|
||||
await appendBareReplHistory(ctx, ln)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
return ln
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,26 @@ import {
|
||||
|
||||
/** Fallback flags when man.options is empty */
|
||||
export const COMPLETION_FLAG_MAP = {
|
||||
ls: ['-a', '-l', '-la', '-h'],
|
||||
grep: ['-i', '-v', '-n', '-c'],
|
||||
find: ['-name', '-type', '-size'],
|
||||
sort: ['-r', '-n', '-u'],
|
||||
rm: ['-r', '-f', '-rf']
|
||||
ls: ['-a', '-l', '-la', '-h', '-1', '-F', '-i', '--color'],
|
||||
grep: ['-i', '-v', '-n', '-c', '-r', '-E', '-F', '--color'],
|
||||
find: ['-name', '-type', '-size', '-path', '-iname', '-print0', '-delete'],
|
||||
sort: ['-r', '-n', '-u', '-h', '-V', '-f', '-k', '-t'],
|
||||
rm: ['-r', '-f', '-rf', '-d', '-v'],
|
||||
curl: ['-f', '-s', '-S', '-L', '-o', '-O', '-I', '-H', '-d', '-X'],
|
||||
wget: ['-q', '-O', '-c', '-S', '-T', '-U'],
|
||||
tar: ['-c', '-x', '-t', '-f', '-v', '-z', '-j', '-J', '-C'],
|
||||
ps: ['-e', '-f', '-u', '-p', '-o'],
|
||||
df: ['-h', '-T', '-i'],
|
||||
du: ['-h', '-s', '-a', '-d', '-c'],
|
||||
cat: ['-n', '-A', '-b', '-e', '-t', '-v'],
|
||||
sed: ['-n', '-e', '-i', '-r', '-E'],
|
||||
awk: ['-F', '-f', '-v'],
|
||||
head: ['-n', '-c', '-v'],
|
||||
tail: ['-n', '-c', '-f', '-F'],
|
||||
xargs: ['-0', '-n', '-I', '-P', '-r'],
|
||||
chmod: ['-R', '-v', '-c'],
|
||||
chown: ['-R', '-h'],
|
||||
kill: ['-l', '-s']
|
||||
}
|
||||
|
||||
const VFS_TIMEOUT_MS = 220
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
runKernelShutdownHooks,
|
||||
stopBareInitd
|
||||
} from './bare-initd.js'
|
||||
import { wrapReadLineWithReplHistoryPersist } from './cli-readline.js'
|
||||
|
||||
/**
|
||||
* Kernel `console` must write to the same stream as the line editor so cursor stays in sync.
|
||||
@@ -138,7 +139,7 @@ export async function createKernelReplSession({
|
||||
)
|
||||
}
|
||||
|
||||
const readLine = async (prompt) => {
|
||||
const coreReadLine = async (prompt) => {
|
||||
if (isReplDebug()) {
|
||||
replDbg(
|
||||
'repl-readLine',
|
||||
@@ -167,6 +168,18 @@ export async function createKernelReplSession({
|
||||
return line
|
||||
}
|
||||
|
||||
const histPersistOn =
|
||||
globalThis.process?.env?.BARE_OS_REPL_HISTORY === '1' ||
|
||||
globalThis.process?.env?.BARE_OS_REPL_HISTORY === 'true'
|
||||
const readLine =
|
||||
!fishRead &&
|
||||
histPersistOn &&
|
||||
ctx &&
|
||||
ctx.personalDrive &&
|
||||
typeof ctx.personalDrive.put === 'function'
|
||||
? wrapReadLineWithReplHistoryPersist(coreReadLine, ctx)
|
||||
: coreReadLine
|
||||
|
||||
async function cleanup() {
|
||||
if (isReplDebug())
|
||||
replDbg('repl', 'cleanup', fishRead ? 'fish teardown' : 'noop')
|
||||
|
||||
@@ -63,6 +63,7 @@ const SHELL_BUILTINS = new Set([
|
||||
'bg',
|
||||
'wait',
|
||||
'suspend-job',
|
||||
'disown',
|
||||
'trap'
|
||||
])
|
||||
|
||||
@@ -1655,7 +1656,29 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
}
|
||||
} else if (name === 'set') {
|
||||
const args = argv.slice(1)
|
||||
if (args.length === 1 && args[0] === '-f') {
|
||||
if (
|
||||
args.length === 1 &&
|
||||
(args[0] === '-o' || args[0] === '+o')
|
||||
) {
|
||||
const on = (v) =>
|
||||
v === '1' || v === 'true' ? 'on' : 'off'
|
||||
origLog.call(
|
||||
ctx.console,
|
||||
`errexit ${on(env.BARE_OS_SHELL_ERREXIT)}`
|
||||
)
|
||||
origLog.call(
|
||||
ctx.console,
|
||||
`nounset ${on(env.BARE_OS_SHELL_NOUNSET)}`
|
||||
)
|
||||
origLog.call(
|
||||
ctx.console,
|
||||
`pipefail ${on(env.BARE_OS_SHELL_PIPEFAIL)}`
|
||||
)
|
||||
origLog.call(
|
||||
ctx.console,
|
||||
`noglob ${on(env.BARE_OS_SHELL_NOGLOB)}`
|
||||
)
|
||||
} else if (args.length === 1 && args[0] === '-f') {
|
||||
env.BARE_OS_SHELL_NOGLOB = '1'
|
||||
} else if (args.length === 1 && args[0] === '+f') {
|
||||
delete env.BARE_OS_SHELL_NOGLOB
|
||||
@@ -1799,8 +1822,20 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
}
|
||||
} else if (name === 'jobs') {
|
||||
const list = ctx.shellBackgroundJobs?.list || []
|
||||
const ja = argv.slice(1)
|
||||
let showPgidOnly = false
|
||||
let longFmt = false
|
||||
for (const a of ja) {
|
||||
if (a === '-p') showPgidOnly = true
|
||||
else if (a === '-l') longFmt = true
|
||||
}
|
||||
if (!list.length) {
|
||||
origLog.call(ctx.console, '')
|
||||
} else if (showPgidOnly) {
|
||||
for (const j of list) {
|
||||
if (typeof j.pgid === 'number')
|
||||
origLog.call(ctx.console, String(j.pgid))
|
||||
}
|
||||
} else {
|
||||
for (const j of list) {
|
||||
let st = 'Running'
|
||||
@@ -1810,9 +1845,13 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
typeof j.pgid === 'number' && typeof j.sid === 'number'
|
||||
? ` sid=${j.sid} pgid=${j.pgid}`
|
||||
: ''
|
||||
const syn =
|
||||
longFmt && typeof j.id === 'number'
|
||||
? ` pid=${4100 + j.id}`
|
||||
: ''
|
||||
origLog.call(
|
||||
ctx.console,
|
||||
`[${j.id}]+ ${st}${pg} ${j.label}`
|
||||
`[${j.id}]+ ${st}${pg}${syn} ${j.label}`
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1890,6 +1929,37 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
j.stopped = true
|
||||
ctx.exitCode = 0
|
||||
}
|
||||
} else if (name === 'disown') {
|
||||
if (!ctx.shellBackgroundJobs || !Array.isArray(ctx.shellBackgroundJobs.list)) {
|
||||
origErr.call(ctx.console, 'disown: no job control')
|
||||
ctx.exitCode = 1
|
||||
} else {
|
||||
const list = ctx.shellBackgroundJobs.list
|
||||
const arg = argv[1]
|
||||
/** @type {typeof list[number][]} */
|
||||
let targets = []
|
||||
if (!arg) {
|
||||
const running = list.filter((j) => j && !j.done)
|
||||
const j = running.length ? running[running.length - 1] : null
|
||||
if (j) targets = [j]
|
||||
} else {
|
||||
const raw = arg.startsWith('%') ? arg.slice(1) : arg
|
||||
const jid = Number.parseInt(raw, 10)
|
||||
if (Number.isFinite(jid)) {
|
||||
targets = list.filter((x) => x && x.id === jid)
|
||||
}
|
||||
}
|
||||
if (!targets.length) {
|
||||
origErr.call(ctx.console, 'disown: no such job')
|
||||
ctx.exitCode = 1
|
||||
} else {
|
||||
for (const t of targets) {
|
||||
const idx = list.indexOf(t)
|
||||
if (idx >= 0) list.splice(idx, 1)
|
||||
}
|
||||
ctx.exitCode = 0
|
||||
}
|
||||
}
|
||||
} else if (name === 'trap') {
|
||||
if (argv[1] === '-l' || argv[1] === '--list') {
|
||||
ctx.console.log('HUP INT KILL TERM PIPE CHLD USR1 USR2 EXIT')
|
||||
|
||||
@@ -3149,6 +3149,112 @@ test('execShellLine set -o pipefail and BARE_OS_PIPESTATUS', async (t) => {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('runBinCommand kill resolves %n and %% via shellBackgroundJobs', async (t) => {
|
||||
const dir = testCorestoreDir('killjob')
|
||||
const store = new Corestore(dir)
|
||||
const drive = new Hyperdrive(store)
|
||||
const personal = new Hyperdrive(store.namespace('pkjob'))
|
||||
await drive.ready()
|
||||
await personal.ready()
|
||||
const killPath = path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'../../kernel/bin/kill'
|
||||
)
|
||||
const killSrc = await readFile(killPath)
|
||||
await drive.put('/bin/kill', killSrc)
|
||||
|
||||
const ctx = testCtx(drive, personal)
|
||||
/** @type {[string, string][]} */
|
||||
const calls = []
|
||||
ctx.bareOsSendSignal = function (target, sig) {
|
||||
calls.push([String(target), String(sig)])
|
||||
}
|
||||
ctx.shellBackgroundJobs = {
|
||||
nextId: 3,
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
pgid: 400,
|
||||
done: false,
|
||||
stopped: false,
|
||||
label: 'a',
|
||||
promise: Promise.resolve('ok')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
pgid: 401,
|
||||
done: false,
|
||||
stopped: false,
|
||||
label: 'b',
|
||||
promise: Promise.resolve('ok')
|
||||
}
|
||||
]
|
||||
}
|
||||
ctx.exitCode = 0
|
||||
await runBinCommand(ctx, ['kill', '-0', '%1'])
|
||||
t.alike(calls[0], ['4101', '0'])
|
||||
calls.length = 0
|
||||
await runBinCommand(ctx, ['kill', '-TERM', '%%'])
|
||||
t.alike(calls[0], ['4102', 'TERM'])
|
||||
await store.close()
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('execShellLine set -o prints shell toggles', async (t) => {
|
||||
const dir = testCorestoreDir('seto-print')
|
||||
const store = new Corestore(dir)
|
||||
const drive = new Hyperdrive(store)
|
||||
const personal = new Hyperdrive(store.namespace('pso'))
|
||||
await drive.ready()
|
||||
await personal.ready()
|
||||
const logs = []
|
||||
const ctx = testCtx(drive, personal)
|
||||
ctx.console = {
|
||||
log: (m) => logs.push(String(m)),
|
||||
error: (...a) => logs.push(a.join(' '))
|
||||
}
|
||||
ctx.exitCode = 0
|
||||
await execShellLine(ctx, 'set -o')
|
||||
t.ok(logs.some((l) => /errexit\s+off/.test(l)))
|
||||
t.ok(logs.some((l) => /pipefail\s+off/.test(l)))
|
||||
await store.close()
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('execShellLine jobs -p prints pgid only', async (t) => {
|
||||
const dir = testCorestoreDir('jobs-p')
|
||||
const store = new Corestore(dir)
|
||||
const drive = new Hyperdrive(store)
|
||||
const personal = new Hyperdrive(store.namespace('pjobs'))
|
||||
await drive.ready()
|
||||
await personal.ready()
|
||||
const logs = []
|
||||
const ctx = testCtx(drive, personal)
|
||||
ctx.console = {
|
||||
log: (m) => logs.push(String(m)),
|
||||
error: (...a) => logs.push(a.join(' '))
|
||||
}
|
||||
ctx.shellBackgroundJobs = {
|
||||
nextId: 2,
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
pgid: 712,
|
||||
sid: 1,
|
||||
done: false,
|
||||
stopped: false,
|
||||
label: 'x',
|
||||
promise: Promise.resolve('ok')
|
||||
}
|
||||
]
|
||||
}
|
||||
ctx.exitCode = 0
|
||||
await execShellLine(ctx, 'jobs -p')
|
||||
t.ok(logs.includes('712'))
|
||||
await store.close()
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('execShellLine errexit stops inside if-then body after failure', async (t) => {
|
||||
const dir = testCorestoreDir('errexit-if')
|
||||
const store = new Corestore(dir)
|
||||
|
||||
@@ -35,7 +35,7 @@ Or `node packages/bare-os-coreutils/build.mjs`.
|
||||
|
||||
## Commands (authoritative list)
|
||||
|
||||
**Source of truth:** **`lib/commands.mjs`** — **`COREUTILS_COMMANDS`** (imported by **`build.mjs`** and **`scripts/build-man-db.mjs`**). Each name must have **`man/pages/<name>.json`**. **150** Tier-1 commands in the current tree (**`sshd`**’s `/bin` body is emitted by **`bare-os-openssh`**); root **`pretest`** runs **`verify-man-coverage.mjs`** against this list (do not hand-maintain a duplicate comma-separated inventory here—use **`lib/commands.mjs`**, **`ls /bin`** in the guest, or **`man -k`**).
|
||||
**Source of truth:** **`lib/commands.mjs`** — **`COREUTILS_COMMANDS`** (imported by **`build.mjs`** and **`scripts/build-man-db.mjs`**). Each name must have **`man/pages/<name>.json`**. **153** Tier-1 commands in the current tree (**`sshd`**’s `/bin` body is emitted by **`bare-os-openssh`**); root **`pretest`** runs **`verify-man-coverage.mjs`** against this list (do not hand-maintain a duplicate comma-separated inventory here—use **`lib/commands.mjs`**, **`ls /bin`** in the guest, or **`man -k`**).
|
||||
|
||||
**`edit`** is a full-screen TTY buffer editor (syntax highlighting, search, save). **`nano`** is built from the same **`src/edit.js`** with the same **`lib/edit-*.js`** preamble; **`/bin/nano`** exists for familiarity, and the stock shell alias **`nano` → `edit`** routes **`nano`** to that utility (see **`packages/bare-os-booter/lib/shell.js`**). Both require a real TTY (**`stdout.isTTY`**).
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ const seederKernelLibBare = join(
|
||||
/** Commands whose /bin script is preceded by extra library sources (no import in src). */
|
||||
const preamble = {
|
||||
md5sum: ['md5.js'],
|
||||
sha224sum: ['sha224.js'],
|
||||
sed: ['sed-engine.js'],
|
||||
awk: ['awk-engine.js'],
|
||||
jq: ['jq-engine.js'],
|
||||
|
||||
@@ -111,7 +111,9 @@ export const COREUTILS_COMMANDS = [
|
||||
'seq',
|
||||
'setfacl',
|
||||
'sha1sum',
|
||||
'sha224sum',
|
||||
'sha256sum',
|
||||
'sha384sum',
|
||||
'sha512sum',
|
||||
'sh',
|
||||
'shuf',
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* SHA-224 (FIPS 180-4) — same compression as SHA-256, distinct IV, output first 224 bits.
|
||||
* Bundled because many runtimes (incl. Node Web Crypto) omit SHA-224 in subtle.digest.
|
||||
*/
|
||||
function bareSha224DigestBytes(u8) {
|
||||
const K = new Uint32Array([
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
|
||||
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
|
||||
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
|
||||
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
|
||||
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
||||
0xc67178f2
|
||||
])
|
||||
const W = new Uint32Array(64)
|
||||
const n = u8.length
|
||||
const bits = BigInt(n) * 8n
|
||||
const bitLenHi = Number((bits >> 32n) & 0xffffffffn)
|
||||
const bitLenLo = Number(bits & 0xffffffffn)
|
||||
const padLen = (56 - ((n + 1) % 64) + 64) % 64
|
||||
const total = n + 1 + padLen + 8
|
||||
const buf = new Uint8Array(total)
|
||||
buf.set(u8)
|
||||
buf[n] = 0x80
|
||||
const view = new DataView(buf.buffer)
|
||||
view.setUint32(total - 8, bitLenHi, false)
|
||||
view.setUint32(total - 4, bitLenLo, false)
|
||||
|
||||
let h0 = 0xc1059ed8
|
||||
let h1 = 0x367cd507
|
||||
let h2 = 0x3070dd17
|
||||
let h3 = 0xf70e5939
|
||||
let h4 = 0xffc00b31
|
||||
let h5 = 0x68581511
|
||||
let h6 = 0x64f98fa7
|
||||
let h7 = 0xbefa4fa4
|
||||
|
||||
const rotr = (x, c) => ((x >>> c) | (x << (32 - c))) >>> 0
|
||||
for (let off = 0; off < total; off += 64) {
|
||||
for (let i = 0; i < 16; i++) W[i] = view.getUint32(off + i * 4, false)
|
||||
for (let i = 16; i < 64; i++) {
|
||||
const s0 = rotr(W[i - 15], 7) ^ rotr(W[i - 15], 18) ^ (W[i - 15] >>> 3)
|
||||
const s1 = rotr(W[i - 2], 17) ^ rotr(W[i - 2], 19) ^ (W[i - 2] >>> 10)
|
||||
W[i] = (W[i - 16] + s0 + W[i - 7] + s1) >>> 0
|
||||
}
|
||||
let a = h0
|
||||
let b = h1
|
||||
let c = h2
|
||||
let d = h3
|
||||
let e = h4
|
||||
let f = h5
|
||||
let g = h6
|
||||
let h = h7
|
||||
for (let i = 0; i < 64; i++) {
|
||||
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)
|
||||
const ch = (e & f) ^ (~e & g)
|
||||
const t1 = (h + S1 + ch + K[i] + W[i]) >>> 0
|
||||
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)
|
||||
const maj = (a & b) ^ (a & c) ^ (b & c)
|
||||
const t2 = (S0 + maj) >>> 0
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = (d + t1) >>> 0
|
||||
d = c
|
||||
c = b
|
||||
b = a
|
||||
a = (t1 + t2) >>> 0
|
||||
}
|
||||
h0 = (h0 + a) >>> 0
|
||||
h1 = (h1 + b) >>> 0
|
||||
h2 = (h2 + c) >>> 0
|
||||
h3 = (h3 + d) >>> 0
|
||||
h4 = (h4 + e) >>> 0
|
||||
h5 = (h5 + f) >>> 0
|
||||
h6 = (h6 + g) >>> 0
|
||||
h7 = (h7 + h) >>> 0
|
||||
}
|
||||
|
||||
const out = new Uint8Array(28)
|
||||
const ov = new DataView(out.buffer)
|
||||
ov.setUint32(0, h0, false)
|
||||
ov.setUint32(4, h1, false)
|
||||
ov.setUint32(8, h2, false)
|
||||
ov.setUint32(12, h3, false)
|
||||
ov.setUint32(16, h4, false)
|
||||
ov.setUint32(20, h5, false)
|
||||
ov.setUint32(24, h6, false)
|
||||
return [...out].map((b) => b.toString(16).padStart(2, '0')).join('')
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "bare-os-shell",
|
||||
"section": 1,
|
||||
"title": "Bare OS interactive shell builtins",
|
||||
"title": "Bare OS interactive shell (Issue 7–inspired subset)",
|
||||
"synopsis": [
|
||||
"# builtins only — no full POSIX sh grammar"
|
||||
"# Interactive session: builtins + /bin via ctx.execLine (see handbook §9)",
|
||||
"# /bin/sh is a separate script runner — see man sh"
|
||||
],
|
||||
"description": "The line-at-a-time shell supports aliases, simple pipelines (simulated), redirection, and the builtins below. Compound commands (if, for, while) are not available.",
|
||||
"description": "The interactive shell runs in the booter: tokenization, pipelines (simulated capture), redirection, AND-OR lists (; && ||), bounded compound commands (if/fi, while/for/case), background jobs (&), optional command substitution ($(…)) when BARE_OS_SHELL_CMDSUBST=1, globbing, and subsets of errexit (-e), nounset (-u), and pipefail. There are no forked subshells and no full POSIX sh grammar. Canonical narrative: handbook ch.9; completion/REPL: docs/reference/shell-completion-and-repl-editor.md.",
|
||||
"options": [],
|
||||
"aliases": [
|
||||
"sh-builtins"
|
||||
@@ -13,9 +14,9 @@
|
||||
"keywords": [
|
||||
"shell",
|
||||
"builtin",
|
||||
"cd",
|
||||
"export",
|
||||
"alias",
|
||||
"pipeline",
|
||||
"jobs",
|
||||
"execLine",
|
||||
"bare-os-shell",
|
||||
"sh-builtins"
|
||||
],
|
||||
@@ -27,7 +28,7 @@
|
||||
"alias name=value ...",
|
||||
"unalias name ..."
|
||||
],
|
||||
"description": "Define or list command aliases. unalias removes definitions."
|
||||
"description": "Define or list command aliases; unalias removes definitions."
|
||||
},
|
||||
{
|
||||
"name": "cd",
|
||||
@@ -64,13 +65,24 @@
|
||||
],
|
||||
"description": "Show or set shell file creation mask (stored in env UMASK)."
|
||||
},
|
||||
{
|
||||
"name": "set",
|
||||
"synopsis": [
|
||||
"set -o",
|
||||
"set +o",
|
||||
"set -e | +e | -u | +u | -f | +f",
|
||||
"set -o errexit|nounset|pipefail",
|
||||
"set +o errexit|nounset|pipefail"
|
||||
],
|
||||
"description": "Toggle errexit (BARE_OS_SHELL_ERREXIT), nounset (BARE_OS_SHELL_NOUNSET), pipefail (BARE_OS_SHELL_PIPEFAIL), noglob (BARE_OS_SHELL_NOGLOB). Use set -o / set +o alone to print current shell options (subset)."
|
||||
},
|
||||
{
|
||||
"name": "command",
|
||||
"synopsis": [
|
||||
"command -v|-V NAME",
|
||||
"command ARGV..."
|
||||
],
|
||||
"description": "Resolve or run a command without using shell functions (none) or aliases for -v/-V."
|
||||
"description": "Resolve or run a command; -v/-V skip aliases."
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
@@ -79,6 +91,46 @@
|
||||
],
|
||||
"description": "Report whether NAME is a builtin or a path under PATH."
|
||||
},
|
||||
{
|
||||
"name": "jobs",
|
||||
"synopsis": [
|
||||
"jobs [-l] [-p]"
|
||||
],
|
||||
"description": "List logical background jobs. -p prints pgid only; -l includes pgid/sid in the listing."
|
||||
},
|
||||
{
|
||||
"name": "fg / bg / wait",
|
||||
"synopsis": [
|
||||
"fg [%job]",
|
||||
"bg [%job]",
|
||||
"wait [n | %n]",
|
||||
"wait -n (with BARE_OS_SHELL_POSIX_MODE=1)"
|
||||
],
|
||||
"description": "Cooperative job control: fg awaits a job; bg resumes stopped jobs; wait waits for jobs by id or all."
|
||||
},
|
||||
{
|
||||
"name": "suspend-job",
|
||||
"synopsis": [
|
||||
"suspend-job [%job]"
|
||||
],
|
||||
"description": "Mark a running background job stopped (logical); resume with fg or bg."
|
||||
},
|
||||
{
|
||||
"name": "disown",
|
||||
"synopsis": [
|
||||
"disown [%job]"
|
||||
],
|
||||
"description": "Remove a job from the jobs table without cancelling its async work (still runs to completion)."
|
||||
},
|
||||
{
|
||||
"name": "trap",
|
||||
"synopsis": [
|
||||
"trap -l",
|
||||
"trap -p",
|
||||
"trap CMD SIGNAL"
|
||||
],
|
||||
"description": "List signals, print handlers, or register synthetic trap handlers (ctx.shellTrapHandlers)."
|
||||
},
|
||||
{
|
||||
"name": "login / logout",
|
||||
"synopsis": [
|
||||
@@ -100,9 +152,20 @@
|
||||
"exit [n]"
|
||||
],
|
||||
"description": "Request booter exit with status n (builtin path)."
|
||||
},
|
||||
{
|
||||
"name": "read",
|
||||
"synopsis": [
|
||||
"read [-r] [NAME ...]"
|
||||
],
|
||||
"description": "Optional when BARE_OS_SHELL_READ_BUILTIN=1; bounded line from shell stdin or readLine."
|
||||
}
|
||||
],
|
||||
"seeAlso": [
|
||||
{
|
||||
"name": "sh",
|
||||
"section": 1
|
||||
},
|
||||
{
|
||||
"name": "help",
|
||||
"section": 1
|
||||
@@ -112,31 +175,27 @@
|
||||
"section": 1
|
||||
}
|
||||
],
|
||||
"bareOsNotes": "Pipelines do not use OS pipes; see handbook ch.4 and ch.9.",
|
||||
"bareOsNotes": "Pipelines use simulated capture (not OS pipes). kill and wait accept %n job specs when shellBackgroundJobs is populated. Full UX (history file, tab menu, Ctrl+R) uses BARE_OS_FISH≠0 on a TTY; see shell-completion-and-repl-editor.md.",
|
||||
"examples": [
|
||||
{
|
||||
"caption": "pipeline (simulated)",
|
||||
"code": "ls -1 /bin | grep man"
|
||||
},
|
||||
{
|
||||
"caption": "errexit + compound",
|
||||
"code": "set -e\nif true; then echo ok; fi"
|
||||
},
|
||||
{
|
||||
"caption": "background job",
|
||||
"code": "sleep 1 &\njobs"
|
||||
},
|
||||
{
|
||||
"caption": "redirect out",
|
||||
"code": "echo hi > ~/hello.txt"
|
||||
},
|
||||
{
|
||||
"caption": "append",
|
||||
"code": "date >> ~/log.txt"
|
||||
},
|
||||
{
|
||||
"caption": "alias + use",
|
||||
"code": "alias ll='ls -la'\nll ~"
|
||||
},
|
||||
{
|
||||
"caption": "export for children",
|
||||
"code": "export EDITOR=ed\nman ls"
|
||||
},
|
||||
{
|
||||
"caption": "temp var for one command",
|
||||
"code": "PATH=/bin man which"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,11 +5,19 @@
|
||||
"synopsis": [
|
||||
"kill [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of kill. Full behavior is defined in packages/bare-os-coreutils/src/kill.js.",
|
||||
"description": "Send a signal to synthetic processes. Targets may be numeric PIDs, kernel/booter/shell names, negative values for logical process groups, or job specs when the interactive shell has background jobs: %n (job id n) or %% (current job), resolved to synthetic PIDs 4100+job.id for ctx.bareOsSendSignal. See handbook ch.9 and bare-os-process-table jobControlSemantics.",
|
||||
"options": [],
|
||||
"keywords": [
|
||||
"kill",
|
||||
"signal",
|
||||
"job",
|
||||
"bare-os",
|
||||
"coreutils"
|
||||
],
|
||||
"seeAlso": [
|
||||
{
|
||||
"name": "bare-os-shell",
|
||||
"section": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"synopsis": [
|
||||
"sh [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of sh. Full behavior is defined in packages/bare-os-coreutils/src/sh.js.",
|
||||
"description": "Runs a shell script file line-by-line via ctx.execLine (same language as the interactive booter shell). This is not the interactive REPL; see man bare-os-shell for session builtins, pipelines, and jobs.",
|
||||
"options": [],
|
||||
"keywords": [
|
||||
"sh",
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "sha224sum",
|
||||
"section": 1,
|
||||
"title": "sha224sum",
|
||||
"synopsis": [
|
||||
"sha224sum [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of sha224sum. Computes SHA-224 via a bundled digest (many runtimes omit SHA-224 in crypto.subtle.digest). Full behavior is defined in packages/bare-os-coreutils/src/sha224sum.js.",
|
||||
"options": [],
|
||||
"keywords": [
|
||||
"sha224sum",
|
||||
"bare-os",
|
||||
"coreutils"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "sha384sum",
|
||||
"section": 1,
|
||||
"title": "sha384sum",
|
||||
"synopsis": [
|
||||
"sha384sum [OPTION]... [OPERAND]..."
|
||||
],
|
||||
"description": "Bare OS implementation of sha384sum. Full behavior is defined in packages/bare-os-coreutils/src/sha384sum.js.",
|
||||
"options": [],
|
||||
"keywords": [
|
||||
"sha384sum",
|
||||
"bare-os",
|
||||
"coreutils"
|
||||
]
|
||||
}
|
||||
@@ -6,6 +6,6 @@
|
||||
"description": "Build JS /bin utilities for bare-operating-system (concat + stage to kernel/)",
|
||||
"scripts": {
|
||||
"build": "node ./scripts/ensure-man-pages.mjs && node ./build.mjs",
|
||||
"test": "node ./test/help-bin-list.test.mjs && node ./test/edit-key-parse.test.mjs && node ./test/edit-teardown.test.mjs && node ./test/baretop-bundle.test.mjs && node ./test/baretop-fixture.test.mjs && node ./test/baretop-compose.test.mjs && node ./test/baretop-incremental.test.mjs && node ./test/baretop-ui-helpers.test.mjs && node ./test/posix-test-int-compare.test.mjs && node ./test/posix-utils-edge.test.mjs && node ./test/posix-golden-issue7.test.mjs && node ./test/getconf-pathconf-union-mirror.test.mjs && node ./test/getconf-posix-shm.test.mjs && node ./test/awk-sed-posix-smoke.test.mjs && node ./test/xattr-acl-utils.test.mjs && node ./test/xcu-issue7-sweep.test.mjs && node ./test/expand-tab-stops.test.mjs && node ./test/pkg-swarm-index-pathcap.test.mjs"
|
||||
"test": "node ./test/help-bin-list.test.mjs && node ./test/edit-key-parse.test.mjs && node ./test/edit-teardown.test.mjs && node ./test/baretop-bundle.test.mjs && node ./test/baretop-fixture.test.mjs && node ./test/baretop-compose.test.mjs && node ./test/baretop-incremental.test.mjs && node ./test/baretop-ui-helpers.test.mjs && node ./test/posix-test-int-compare.test.mjs && node ./test/posix-utils-edge.test.mjs && node ./test/posix-golden-issue7.test.mjs && node ./test/getconf-pathconf-union-mirror.test.mjs && node ./test/getconf-posix-shm.test.mjs && node ./test/awk-sed-posix-smoke.test.mjs && node ./test/xattr-acl-utils.test.mjs && node ./test/xcu-issue7-sweep.test.mjs && node ./test/expand-tab-stops.test.mjs && node ./test/pkg-swarm-index-pathcap.test.mjs && node ./test/sha224-sha384-sum.test.mjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -933,18 +933,21 @@ function shellPage() {
|
||||
return {
|
||||
name: 'bare-os-shell',
|
||||
section: 1,
|
||||
title: 'Bare OS interactive shell builtins',
|
||||
synopsis: ['# builtins only — no full POSIX sh grammar'],
|
||||
title: 'Bare OS interactive shell (Issue 7–inspired subset)',
|
||||
synopsis: [
|
||||
'# Interactive session: builtins + /bin via ctx.execLine (see handbook §9)',
|
||||
'# /bin/sh is a separate script runner — see man sh'
|
||||
],
|
||||
description:
|
||||
'The line-at-a-time shell supports aliases, simple pipelines (simulated), redirection, and the builtins below. Compound commands (if, for, while) are not available.',
|
||||
'The interactive shell runs in the booter: tokenization, pipelines (simulated capture), redirection, AND-OR lists (; && ||), bounded compound commands (if/fi, while/for/case), background jobs (&), optional command substitution ($(…)) when BARE_OS_SHELL_CMDSUBST=1, globbing, and subsets of errexit (-e), nounset (-u), and pipefail. There are no forked subshells and no full POSIX sh grammar. Canonical narrative: handbook ch.9; completion/REPL: docs/reference/shell-completion-and-repl-editor.md.',
|
||||
options: [],
|
||||
aliases: ['sh-builtins'],
|
||||
keywords: [
|
||||
'shell',
|
||||
'builtin',
|
||||
'cd',
|
||||
'export',
|
||||
'alias',
|
||||
'pipeline',
|
||||
'jobs',
|
||||
'execLine',
|
||||
'bare-os-shell',
|
||||
'sh-builtins'
|
||||
],
|
||||
@@ -953,7 +956,7 @@ function shellPage() {
|
||||
name: 'alias',
|
||||
synopsis: ['alias', 'alias name=value ...', 'unalias name ...'],
|
||||
description:
|
||||
'Define or list command aliases. unalias removes definitions.'
|
||||
'Define or list command aliases; unalias removes definitions.'
|
||||
},
|
||||
{
|
||||
name: 'cd',
|
||||
@@ -982,17 +985,63 @@ function shellPage() {
|
||||
description:
|
||||
'Show or set shell file creation mask (stored in env UMASK).'
|
||||
},
|
||||
{
|
||||
name: 'set',
|
||||
synopsis: [
|
||||
'set -o',
|
||||
'set +o',
|
||||
'set -e | +e | -u | +u | -f | +f',
|
||||
'set -o errexit|nounset|pipefail',
|
||||
'set +o errexit|nounset|pipefail'
|
||||
],
|
||||
description:
|
||||
'Toggle errexit (BARE_OS_SHELL_ERREXIT), nounset (BARE_OS_SHELL_NOUNSET), pipefail (BARE_OS_SHELL_PIPEFAIL), noglob (BARE_OS_SHELL_NOGLOB). Use set -o / set +o alone to print current shell options (subset).'
|
||||
},
|
||||
{
|
||||
name: 'command',
|
||||
synopsis: ['command -v|-V NAME', 'command ARGV...'],
|
||||
description:
|
||||
'Resolve or run a command without using shell functions (none) or aliases for -v/-V.'
|
||||
description: 'Resolve or run a command; -v/-V skip aliases.'
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
synopsis: ['type NAME'],
|
||||
description: 'Report whether NAME is a builtin or a path under PATH.'
|
||||
},
|
||||
{
|
||||
name: 'jobs',
|
||||
synopsis: ['jobs [-l] [-p]'],
|
||||
description:
|
||||
'List logical background jobs. -p prints pgid only; -l includes pgid/sid in the listing.'
|
||||
},
|
||||
{
|
||||
name: 'fg / bg / wait',
|
||||
synopsis: [
|
||||
'fg [%job]',
|
||||
'bg [%job]',
|
||||
'wait [n | %n]',
|
||||
'wait -n (with BARE_OS_SHELL_POSIX_MODE=1)'
|
||||
],
|
||||
description:
|
||||
'Cooperative job control: fg awaits a job; bg resumes stopped jobs; wait waits for jobs by id or all.'
|
||||
},
|
||||
{
|
||||
name: 'suspend-job',
|
||||
synopsis: ['suspend-job [%job]'],
|
||||
description:
|
||||
'Mark a running background job stopped (logical); resume with fg or bg.'
|
||||
},
|
||||
{
|
||||
name: 'disown',
|
||||
synopsis: ['disown [%job]'],
|
||||
description:
|
||||
'Remove a job from the jobs table without cancelling its async work (still runs to completion).'
|
||||
},
|
||||
{
|
||||
name: 'trap',
|
||||
synopsis: ['trap -l', 'trap -p', 'trap CMD SIGNAL'],
|
||||
description:
|
||||
'List signals, print handlers, or register synthetic trap handlers (ctx.shellTrapHandlers).'
|
||||
},
|
||||
{
|
||||
name: 'login / logout',
|
||||
synopsis: ['login [--new] passphrase...', 'logout [--save]'],
|
||||
@@ -1008,20 +1057,30 @@ function shellPage() {
|
||||
name: 'exit',
|
||||
synopsis: ['exit [n]'],
|
||||
description: 'Request booter exit with status n (builtin path).'
|
||||
},
|
||||
{
|
||||
name: 'read',
|
||||
synopsis: ['read [-r] [NAME ...]'],
|
||||
description:
|
||||
'Optional when BARE_OS_SHELL_READ_BUILTIN=1; bounded line from shell stdin or readLine.'
|
||||
}
|
||||
],
|
||||
seeAlso: [
|
||||
{ name: 'sh', section: 1 },
|
||||
{ name: 'help', section: 1 },
|
||||
{ name: 'man', section: 1 }
|
||||
],
|
||||
bareOsNotes: 'Pipelines do not use OS pipes; see handbook ch.4 and ch.9.',
|
||||
bareOsNotes:
|
||||
'Pipelines use simulated capture (not OS pipes). kill and wait accept %n job specs when shellBackgroundJobs is populated. Full UX (history file, tab menu, Ctrl+R) uses BARE_OS_FISH≠0 on a TTY; see shell-completion-and-repl-editor.md.',
|
||||
examples: [
|
||||
{ caption: 'pipeline (simulated)', code: 'ls -1 /bin | grep man' },
|
||||
{
|
||||
caption: 'errexit + compound',
|
||||
code: 'set -e\nif true; then echo ok; fi'
|
||||
},
|
||||
{ caption: 'background job', code: 'sleep 1 &\njobs' },
|
||||
{ caption: 'redirect out', code: 'echo hi > ~/hello.txt' },
|
||||
{ caption: 'append', code: 'date >> ~/log.txt' },
|
||||
{ caption: 'alias + use', code: "alias ll='ls -la'\nll ~" },
|
||||
{ caption: 'export for children', code: 'export EDITOR=ed\nman ls' },
|
||||
{ caption: 'temp var for one command', code: 'PATH=/bin man which' }
|
||||
{ caption: 'alias + use', code: "alias ll='ls -la'\nll ~" }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
/**
|
||||
* Resolve job spec %n / %% to synthetic PID (4100+job.id) for ctx.bareOsSendSignal.
|
||||
* Matches fg/wait job selection: %% is latest non-done job.
|
||||
* @param {string} raw
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @returns {string} numeric pid, pgid negative form, or passthrough token
|
||||
*/
|
||||
function bareOsKillResolveTarget(raw, ctx) {
|
||||
const s = String(raw == null ? '' : raw).trim()
|
||||
if (!s.startsWith('%')) return s
|
||||
const list =
|
||||
ctx.shellBackgroundJobs &&
|
||||
typeof ctx.shellBackgroundJobs === 'object' &&
|
||||
Array.isArray(ctx.shellBackgroundJobs.list)
|
||||
? ctx.shellBackgroundJobs.list
|
||||
: []
|
||||
const spec = s.slice(1)
|
||||
if (spec === '%' || spec === '') {
|
||||
const running = list.filter((j) => j && !j.done)
|
||||
const j = running.length ? running[running.length - 1] : null
|
||||
if (!j) throw new Error('kill: no current job')
|
||||
return String(4100 + j.id)
|
||||
}
|
||||
const id = Number.parseInt(spec, 10)
|
||||
if (!Number.isFinite(id))
|
||||
throw new Error('kill: invalid job specification: ' + raw)
|
||||
const j = list.find((x) => x && x.id === id)
|
||||
if (!j) throw new Error('kill: %' + id + ': no such job')
|
||||
return String(4100 + j.id)
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const args = argv.slice(1)
|
||||
let signal = 'TERM'
|
||||
@@ -33,7 +64,9 @@ async function run(ctx, argv) {
|
||||
}
|
||||
|
||||
if (targets.length === 0) {
|
||||
ctx.console.error('usage: kill [-s SIGNAL | -SIGNAL] <pid|name>...')
|
||||
ctx.console.error(
|
||||
'usage: kill [-s SIGNAL | -SIGNAL] <pid|name|%job|%%>...'
|
||||
)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
@@ -47,7 +80,8 @@ async function run(ctx, argv) {
|
||||
let failed = 0
|
||||
for (const t of targets) {
|
||||
try {
|
||||
send.call(ctx, t, signal)
|
||||
const resolved = bareOsKillResolveTarget(t, ctx)
|
||||
send.call(ctx, resolved, signal)
|
||||
} catch (e) {
|
||||
failed++
|
||||
ctx.console.error('kill: ' + t + ': ' + (e?.message || String(e)))
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* sha224sum — compute SHA-224 checksums (hex), GNU-like output line.
|
||||
* Uses bundled SHA-224 (many runtimes omit SHA-224 in crypto.subtle.digest).
|
||||
*/
|
||||
async function run(ctx, argv) {
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha224sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha224sum: unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = bareSha224DigestBytes(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha224sum: ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha224sum: ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
one(p, b)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
async function sha384Hex(u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error('crypto.subtle.digest (SHA-384) is not available')
|
||||
}
|
||||
const hash = await subtle.digest('SHA-384', u8)
|
||||
return [...new Uint8Array(hash)]
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha384sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha384sum: unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await sha384Hex(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha384sum: ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha384sum: ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* SHA-224 bundled digest vectors; SHA-384 via Web Crypto (same as sha384sum command).
|
||||
*/
|
||||
import { readFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import vm from 'node:vm'
|
||||
import test from 'brittle'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const sha224Lib = path.join(__dirname, '../lib/sha224.js')
|
||||
|
||||
function loadBareSha224() {
|
||||
const src = readFileSync(sha224Lib, 'utf8')
|
||||
const ctx = {}
|
||||
vm.createContext(ctx)
|
||||
vm.runInContext(src + '\nthis.__fn = bareSha224DigestBytes;', ctx)
|
||||
return ctx.__fn
|
||||
}
|
||||
|
||||
test('bareSha224DigestBytes matches known vectors', async (t) => {
|
||||
const bareSha224DigestBytes = loadBareSha224()
|
||||
t.is(
|
||||
bareSha224DigestBytes(new Uint8Array(0)),
|
||||
'd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f'
|
||||
)
|
||||
t.is(
|
||||
bareSha224DigestBytes(new TextEncoder().encode('abc')),
|
||||
'23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7'
|
||||
)
|
||||
})
|
||||
|
||||
test('SHA-384 empty and abc via subtle.digest', async (t) => {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle?.digest) {
|
||||
t.pass('skip: no Web Crypto subtle')
|
||||
return
|
||||
}
|
||||
async function hex384(u8) {
|
||||
const hash = await subtle.digest('SHA-384', u8)
|
||||
return [...new Uint8Array(hash)]
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
t.is(
|
||||
await hex384(new Uint8Array(0)),
|
||||
'38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b'
|
||||
)
|
||||
const abc = new TextEncoder().encode('abc')
|
||||
t.is(
|
||||
await hex384(abc),
|
||||
'cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7'
|
||||
)
|
||||
})
|
||||
@@ -19,7 +19,7 @@ Files in this directory are **read from disk by the seeder** (or copied into `pa
|
||||
## Contents
|
||||
|
||||
- `**init.js`** — Kernel entry: must define `async function start(ctx)`. Boot order: `**/etc/os-release**` → `**/etc/motd**` → optional `**/etc/bare-os/rc.profile.<profile>**` (profile from `**BARE_OS_BOOT_PROFILE**` or first line of `**/etc/bare-os/profile**`; the booter mirrors the resolved name in `**ctx.env.BARE_OS_BOOT_PROFILE_RESOLVED**` and `**/run/bare-os/boot_profile**`) → `**/etc/bare-os/rc**` → `**/etc/bare-os/rc.d/***` (sorted; digit-prefixed names only; skip dotfiles, `*~`, `README*`, `*.md`; optional `**BARE_OS_RC_D_SKIP**` comma list and `**prefix***` patterns) → optional `**/etc/bare-os/rc.local**` → `**/etc/bare-os/kernel.d/***` (same rules as `**rc.d**`) → banner → when `**BARE_OS_SKIP_REPL**`, optional **onboot** lines from `**BARE_OS_ONBOOT`** or `**/etc/bare-os/onboot**` → `**readLine` / `execLine**` loop. Boot `**execLine**` errors in trusted snippets are logged; with `**BARE_OS_BOOT_STRICT=1**` or `**true**`, the first throw calls `**requestBooterExit(1)**` and stops later boot phases. Custom kernels may call `**ctx.registerKernelShutdownHook(fn)**` before initd disposers; use `**ctx.bareOsRuntimeCaps**` for limits, pseudo paths, and `**features**` (`[developer-guide/02-the-context-object.md](../developer-guide/02-the-context-object.md)`).
|
||||
- `**bin/**` — **Tier-1 utilities** built by [bare-os-coreutils](../packages/bare-os-coreutils/README.md) plus `**sshd`** / `**bare-sshd**` from [bare-os-openssh](../packages/bare-os-openssh/) (**150** commands in `**COREUTILS_COMMANDS`**; `**sshd**` is listed for man/help but its concatenated script is emitted by the openssh package build, not coreutils `**src/**`). Each file is `**runtime.js**` + optional preamble (`**lib/md5.js**` for `**md5sum**`, `**lib/*-engine.js**` for `**sed**`/`**awk**`, `**jq-engine.js**`, `**lib/man-render.js**`, `**lib/edit-*.js**` for `**edit**`/`**nano**`, lscolors for `**ls**`/`**dircolors**`, …) + `**async function run(ctx, argv)**` (no ESM `**import**` in `**src/**`). `**/bin/nano**` duplicates `**/bin/edit**` for familiarity; the shell’s default `**nano` → `edit**` alias uses the `**edit**` command name after expansion. `**dir**`/`**vdir**` invoke `**ls**` via `**ctx.runBinCommand**`.
|
||||
- `**bin/**` — **Tier-1 utilities** built by [bare-os-coreutils](../packages/bare-os-coreutils/README.md) plus `**sshd`** / `**bare-sshd**` from [bare-os-openssh](../packages/bare-os-openssh/) (**153** commands in `**COREUTILS_COMMANDS`**; `**sshd**` is listed for man/help but its concatenated script is emitted by the openssh package build, not coreutils `**src/**`). Each file is `**runtime.js**` + optional preamble (`**lib/md5.js**` for `**md5sum**`, `**lib/sha224.js**` for `**sha224sum**`, `**lib/*-engine.js**` for `**sed**`/`**awk**`, `**jq-engine.js**`, `**lib/man-render.js**`, `**lib/edit-*.js**` for `**edit**`/`**nano**`, lscolors for `**ls**`/`**dircolors**`, …) + `**async function run(ctx, argv)**` (no ESM `**import**` in `**src/**`). `**/bin/nano**` duplicates `**/bin/edit**` for familiarity; the shell’s default `**nano` → `edit**` alias uses the `**edit**` command name after expansion. `**dir**`/`**vdir**` invoke `**ls**` via `**ctx.runBinCommand**`.
|
||||
- `**lib/bare/**` — Optional IIFE bundles + `**manifest.json**` for `**ctx.bare**` drive merge, built by [bare-os-bare-libs](../packages/bare-os-bare-libs/README.md). Same trust model as `**bin/**` (trusted seeded image).
|
||||
- `**share/man/man.json**` — Merged manual database for `**/bin/man**` (built by `**bare-os-coreutils**`; see [handbook ch.10](../handbook/10-manpages-and-online-help.md)).
|
||||
- `**etc/os-release**` — Static OS metadata (`NAME`, `VERSION`, …).
|
||||
|
||||
@@ -87,7 +87,7 @@ function bareOsEmitRaw(ctx, chunk) {
|
||||
return false
|
||||
}
|
||||
|
||||
var BARE_OS_HELP_BIN_SPACED = "arch awk baretop base32 base64 basename basenc btop bundlebee cat chgrp chmod chown cksum clear cmp comm cp crontab curl cut date dd df diff dir dircolors dirname du echo edit env exit expand expr factor false find fmt fold getconf getfacl git git-pear grep groups hdms head help holesail hostid hostname hrpc iconv id install join journalctl jq kernel-boot-diff kernel-doctor kernel-explain kernel-fsck kernel-home-snapshot kernel-manifest-validate kernel-preflight kernel-triage kill link ln logger login logname logout ls man md5sum mkdir mkfifo mktemp mount mv nano nice nl nohup nproc numfmt od oidc-publish openssl openssl paste patch pathcap-verify pathchk pear-runtime-matrix pkg-swarm-index pr printenv printf procstat ps pwd readlink realpath rev rm rmdir savevault sed seq setfacl sh sha1sum sha256sum sha512sum shuf sidecar sleep sort split ssh-keygen ssh-keygen sshd sshd stat sum sync systemctl tac tail tar tar tee test theme time timeout touch tr true truncate tsort tty ulimit umount uname unexpand uniq unlink uptime users vdir wc wget which who whoami xargs xattr yes"
|
||||
var BARE_OS_HELP_BIN_SPACED = "arch awk baretop base32 base64 basename basenc btop bundlebee cat chgrp chmod chown cksum clear cmp comm cp crontab curl cut date dd df diff dir dircolors dirname du echo edit env exit expand expr factor false find fmt fold getconf getfacl git git-pear grep groups hdms head help holesail hostid hostname hrpc iconv id install join journalctl jq kernel-boot-diff kernel-doctor kernel-explain kernel-fsck kernel-home-snapshot kernel-manifest-validate kernel-preflight kernel-triage kill link ln logger login logname logout ls man md5sum mkdir mkfifo mktemp mount mv nano nice nl nohup nproc numfmt od oidc-publish openssl openssl paste patch pathcap-verify pathchk pear-runtime-matrix pkg-swarm-index pr printenv printf procstat ps pwd readlink realpath rev rm rmdir savevault sed seq setfacl sh sha1sum sha224sum sha256sum sha384sum sha512sum shuf sidecar sleep sort split ssh-keygen ssh-keygen sshd sshd stat sum sync systemctl tac tail tar tar tee test theme time timeout touch tr true truncate tsort tty ulimit umount uname unexpand uniq unlink uptime users vdir wc wget which who whoami xargs xattr yes"
|
||||
async function run(ctx, argv) {
|
||||
ctx.console.log(
|
||||
'Bare OS — default user: guest | shell builtins: alias, barerc, cd, command, export, exit, login, logout, readonly, type, umask, unalias, unset, : | /bin: ' +
|
||||
|
||||
@@ -87,6 +87,37 @@ function bareOsEmitRaw(ctx, chunk) {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve job spec %n / %% to synthetic PID (4100+job.id) for ctx.bareOsSendSignal.
|
||||
* Matches fg/wait job selection: %% is latest non-done job.
|
||||
* @param {string} raw
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @returns {string} numeric pid, pgid negative form, or passthrough token
|
||||
*/
|
||||
function bareOsKillResolveTarget(raw, ctx) {
|
||||
const s = String(raw == null ? '' : raw).trim()
|
||||
if (!s.startsWith('%')) return s
|
||||
const list =
|
||||
ctx.shellBackgroundJobs &&
|
||||
typeof ctx.shellBackgroundJobs === 'object' &&
|
||||
Array.isArray(ctx.shellBackgroundJobs.list)
|
||||
? ctx.shellBackgroundJobs.list
|
||||
: []
|
||||
const spec = s.slice(1)
|
||||
if (spec === '%' || spec === '') {
|
||||
const running = list.filter((j) => j && !j.done)
|
||||
const j = running.length ? running[running.length - 1] : null
|
||||
if (!j) throw new Error('kill: no current job')
|
||||
return String(4100 + j.id)
|
||||
}
|
||||
const id = Number.parseInt(spec, 10)
|
||||
if (!Number.isFinite(id))
|
||||
throw new Error('kill: invalid job specification: ' + raw)
|
||||
const j = list.find((x) => x && x.id === id)
|
||||
if (!j) throw new Error('kill: %' + id + ': no such job')
|
||||
return String(4100 + j.id)
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const args = argv.slice(1)
|
||||
let signal = 'TERM'
|
||||
@@ -122,7 +153,9 @@ async function run(ctx, argv) {
|
||||
}
|
||||
|
||||
if (targets.length === 0) {
|
||||
ctx.console.error('usage: kill [-s SIGNAL | -SIGNAL] <pid|name>...')
|
||||
ctx.console.error(
|
||||
'usage: kill [-s SIGNAL | -SIGNAL] <pid|name|%job|%%>...'
|
||||
)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
@@ -136,7 +169,8 @@ async function run(ctx, argv) {
|
||||
let failed = 0
|
||||
for (const t of targets) {
|
||||
try {
|
||||
send.call(ctx, t, signal)
|
||||
const resolved = bareOsKillResolveTarget(t, ctx)
|
||||
send.call(ctx, resolved, signal)
|
||||
} catch (e) {
|
||||
failed++
|
||||
ctx.console.error('kill: ' + t + ': ' + (e?.message || String(e)))
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/* BARE_OS_BIN_API 1.0.0 — bump when staged /bin script semantics change (see developer guide). */
|
||||
/** Shared helpers for drive-resident /bin scripts (prepended before each command). */
|
||||
function bareStdin(ctx) {
|
||||
return typeof ctx.shellStdin === 'string' ? ctx.shellStdin : ''
|
||||
}
|
||||
|
||||
/** @param {number} mode @param {'file' | 'directory' | 'symlink'} type */
|
||||
function bareFormatModeString(mode, type) {
|
||||
const typeChar = type === 'directory' ? 'd' : type === 'symlink' ? 'l' : '-'
|
||||
const perm = mode & 0o777
|
||||
const r = (bit) => (perm & bit ? 'r' : '-')
|
||||
const w = (bit) => (perm & bit ? 'w' : '-')
|
||||
const x = (bit) => (perm & bit ? 'x' : '-')
|
||||
return (
|
||||
typeChar +
|
||||
r(0o400) +
|
||||
w(0o200) +
|
||||
x(0o100) +
|
||||
r(0o040) +
|
||||
w(0o020) +
|
||||
x(0o010) +
|
||||
r(0o004) +
|
||||
w(0o002) +
|
||||
x(0o001)
|
||||
)
|
||||
}
|
||||
|
||||
/** @param {number} mtimeMs @param {number} [nowMs] */
|
||||
function bareFormatLsMtime(mtimeMs, nowMs) {
|
||||
const now = nowMs != null ? nowMs : Date.now()
|
||||
const d = new Date(mtimeMs)
|
||||
const months = [
|
||||
'Jan',
|
||||
'Feb',
|
||||
'Mar',
|
||||
'Apr',
|
||||
'May',
|
||||
'Jun',
|
||||
'Jul',
|
||||
'Aug',
|
||||
'Sep',
|
||||
'Oct',
|
||||
'Nov',
|
||||
'Dec'
|
||||
]
|
||||
const mon = months[d.getMonth()]
|
||||
const day = String(d.getDate()).padStart(2, ' ')
|
||||
const sixMo = 180 * 24 * 3600 * 1000
|
||||
if (Math.abs(now - mtimeMs) > sixMo) {
|
||||
const yr = String(d.getFullYear()).padStart(4, ' ')
|
||||
return mon + ' ' + day + ' ' + yr
|
||||
}
|
||||
const hh = String(d.getHours()).padStart(2, '0')
|
||||
const mm = String(d.getMinutes()).padStart(2, '0')
|
||||
return mon + ' ' + day + ' ' + hh + ':' + mm
|
||||
}
|
||||
|
||||
/** @param {number} size */
|
||||
function barePosixBlocks(size) {
|
||||
return Math.ceil(Number(size) / 512) || 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw stdout for NUL/binary when **`process.stdout.write`** is missing.
|
||||
* If **`ctx.bareOsBinWrite(Uint8Array|string)`** is set (tests / host), use it.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string | Uint8Array} chunk
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function bareOsEmitRaw(ctx, chunk) {
|
||||
if (typeof ctx.bareOsBinWrite === 'function') {
|
||||
const b4 = ctx.b4a
|
||||
const u8 =
|
||||
typeof chunk === 'string'
|
||||
? b4 && typeof b4.from === 'function'
|
||||
? b4.from(chunk)
|
||||
: new TextEncoder().encode(chunk)
|
||||
: chunk
|
||||
ctx.bareOsBinWrite(u8 instanceof Uint8Array ? u8 : new Uint8Array(u8))
|
||||
return true
|
||||
}
|
||||
const w = globalThis.process?.stdout?.write
|
||||
if (typeof w === 'function') {
|
||||
w.call(globalThis.process.stdout, chunk)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA-224 (FIPS 180-4) — same compression as SHA-256, distinct IV, output first 224 bits.
|
||||
* Bundled because many runtimes (incl. Node Web Crypto) omit SHA-224 in subtle.digest.
|
||||
*/
|
||||
function bareSha224DigestBytes(u8) {
|
||||
const K = new Uint32Array([
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
|
||||
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
|
||||
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
|
||||
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
|
||||
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
||||
0xc67178f2
|
||||
])
|
||||
const W = new Uint32Array(64)
|
||||
const n = u8.length
|
||||
const bits = BigInt(n) * 8n
|
||||
const bitLenHi = Number((bits >> 32n) & 0xffffffffn)
|
||||
const bitLenLo = Number(bits & 0xffffffffn)
|
||||
const padLen = (56 - ((n + 1) % 64) + 64) % 64
|
||||
const total = n + 1 + padLen + 8
|
||||
const buf = new Uint8Array(total)
|
||||
buf.set(u8)
|
||||
buf[n] = 0x80
|
||||
const view = new DataView(buf.buffer)
|
||||
view.setUint32(total - 8, bitLenHi, false)
|
||||
view.setUint32(total - 4, bitLenLo, false)
|
||||
|
||||
let h0 = 0xc1059ed8
|
||||
let h1 = 0x367cd507
|
||||
let h2 = 0x3070dd17
|
||||
let h3 = 0xf70e5939
|
||||
let h4 = 0xffc00b31
|
||||
let h5 = 0x68581511
|
||||
let h6 = 0x64f98fa7
|
||||
let h7 = 0xbefa4fa4
|
||||
|
||||
const rotr = (x, c) => ((x >>> c) | (x << (32 - c))) >>> 0
|
||||
for (let off = 0; off < total; off += 64) {
|
||||
for (let i = 0; i < 16; i++) W[i] = view.getUint32(off + i * 4, false)
|
||||
for (let i = 16; i < 64; i++) {
|
||||
const s0 = rotr(W[i - 15], 7) ^ rotr(W[i - 15], 18) ^ (W[i - 15] >>> 3)
|
||||
const s1 = rotr(W[i - 2], 17) ^ rotr(W[i - 2], 19) ^ (W[i - 2] >>> 10)
|
||||
W[i] = (W[i - 16] + s0 + W[i - 7] + s1) >>> 0
|
||||
}
|
||||
let a = h0
|
||||
let b = h1
|
||||
let c = h2
|
||||
let d = h3
|
||||
let e = h4
|
||||
let f = h5
|
||||
let g = h6
|
||||
let h = h7
|
||||
for (let i = 0; i < 64; i++) {
|
||||
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)
|
||||
const ch = (e & f) ^ (~e & g)
|
||||
const t1 = (h + S1 + ch + K[i] + W[i]) >>> 0
|
||||
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)
|
||||
const maj = (a & b) ^ (a & c) ^ (b & c)
|
||||
const t2 = (S0 + maj) >>> 0
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = (d + t1) >>> 0
|
||||
d = c
|
||||
c = b
|
||||
b = a
|
||||
a = (t1 + t2) >>> 0
|
||||
}
|
||||
h0 = (h0 + a) >>> 0
|
||||
h1 = (h1 + b) >>> 0
|
||||
h2 = (h2 + c) >>> 0
|
||||
h3 = (h3 + d) >>> 0
|
||||
h4 = (h4 + e) >>> 0
|
||||
h5 = (h5 + f) >>> 0
|
||||
h6 = (h6 + g) >>> 0
|
||||
h7 = (h7 + h) >>> 0
|
||||
}
|
||||
|
||||
const out = new Uint8Array(28)
|
||||
const ov = new DataView(out.buffer)
|
||||
ov.setUint32(0, h0, false)
|
||||
ov.setUint32(4, h1, false)
|
||||
ov.setUint32(8, h2, false)
|
||||
ov.setUint32(12, h3, false)
|
||||
ov.setUint32(16, h4, false)
|
||||
ov.setUint32(20, h5, false)
|
||||
ov.setUint32(24, h6, false)
|
||||
return [...out].map((b) => b.toString(16).padStart(2, '0')).join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* sha224sum — compute SHA-224 checksums (hex), GNU-like output line.
|
||||
* Uses bundled SHA-224 (many runtimes omit SHA-224 in crypto.subtle.digest).
|
||||
*/
|
||||
async function run(ctx, argv) {
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha224sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha224sum: unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = bareSha224DigestBytes(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha224sum: ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha224sum: ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
one(p, b)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/* BARE_OS_BIN_API 1.0.0 — bump when staged /bin script semantics change (see developer guide). */
|
||||
/** Shared helpers for drive-resident /bin scripts (prepended before each command). */
|
||||
function bareStdin(ctx) {
|
||||
return typeof ctx.shellStdin === 'string' ? ctx.shellStdin : ''
|
||||
}
|
||||
|
||||
/** @param {number} mode @param {'file' | 'directory' | 'symlink'} type */
|
||||
function bareFormatModeString(mode, type) {
|
||||
const typeChar = type === 'directory' ? 'd' : type === 'symlink' ? 'l' : '-'
|
||||
const perm = mode & 0o777
|
||||
const r = (bit) => (perm & bit ? 'r' : '-')
|
||||
const w = (bit) => (perm & bit ? 'w' : '-')
|
||||
const x = (bit) => (perm & bit ? 'x' : '-')
|
||||
return (
|
||||
typeChar +
|
||||
r(0o400) +
|
||||
w(0o200) +
|
||||
x(0o100) +
|
||||
r(0o040) +
|
||||
w(0o020) +
|
||||
x(0o010) +
|
||||
r(0o004) +
|
||||
w(0o002) +
|
||||
x(0o001)
|
||||
)
|
||||
}
|
||||
|
||||
/** @param {number} mtimeMs @param {number} [nowMs] */
|
||||
function bareFormatLsMtime(mtimeMs, nowMs) {
|
||||
const now = nowMs != null ? nowMs : Date.now()
|
||||
const d = new Date(mtimeMs)
|
||||
const months = [
|
||||
'Jan',
|
||||
'Feb',
|
||||
'Mar',
|
||||
'Apr',
|
||||
'May',
|
||||
'Jun',
|
||||
'Jul',
|
||||
'Aug',
|
||||
'Sep',
|
||||
'Oct',
|
||||
'Nov',
|
||||
'Dec'
|
||||
]
|
||||
const mon = months[d.getMonth()]
|
||||
const day = String(d.getDate()).padStart(2, ' ')
|
||||
const sixMo = 180 * 24 * 3600 * 1000
|
||||
if (Math.abs(now - mtimeMs) > sixMo) {
|
||||
const yr = String(d.getFullYear()).padStart(4, ' ')
|
||||
return mon + ' ' + day + ' ' + yr
|
||||
}
|
||||
const hh = String(d.getHours()).padStart(2, '0')
|
||||
const mm = String(d.getMinutes()).padStart(2, '0')
|
||||
return mon + ' ' + day + ' ' + hh + ':' + mm
|
||||
}
|
||||
|
||||
/** @param {number} size */
|
||||
function barePosixBlocks(size) {
|
||||
return Math.ceil(Number(size) / 512) || 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw stdout for NUL/binary when **`process.stdout.write`** is missing.
|
||||
* If **`ctx.bareOsBinWrite(Uint8Array|string)`** is set (tests / host), use it.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string | Uint8Array} chunk
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function bareOsEmitRaw(ctx, chunk) {
|
||||
if (typeof ctx.bareOsBinWrite === 'function') {
|
||||
const b4 = ctx.b4a
|
||||
const u8 =
|
||||
typeof chunk === 'string'
|
||||
? b4 && typeof b4.from === 'function'
|
||||
? b4.from(chunk)
|
||||
: new TextEncoder().encode(chunk)
|
||||
: chunk
|
||||
ctx.bareOsBinWrite(u8 instanceof Uint8Array ? u8 : new Uint8Array(u8))
|
||||
return true
|
||||
}
|
||||
const w = globalThis.process?.stdout?.write
|
||||
if (typeof w === 'function') {
|
||||
w.call(globalThis.process.stdout, chunk)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async function sha384Hex(u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error('crypto.subtle.digest (SHA-384) is not available')
|
||||
}
|
||||
const hash = await subtle.digest('SHA-384', u8)
|
||||
return [...new Uint8Array(hash)]
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha384sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha384sum: unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await sha384Hex(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha384sum: ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha384sum: ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema": 2,
|
||||
"profileId": "bare-os-posix-like",
|
||||
"generatedAt": "2026-04-09T23:26:09.246Z",
|
||||
"generatedAt": "2026-04-21T21:25:44.827Z",
|
||||
"note": "Sparse POSIX Issue 7 coverage hints for /bin utilities. Omitted command names are not yet profiled here.",
|
||||
"commandIndex": [
|
||||
{
|
||||
@@ -444,10 +444,18 @@
|
||||
"name": "sha1sum",
|
||||
"tier": "tier1_bin"
|
||||
},
|
||||
{
|
||||
"name": "sha224sum",
|
||||
"tier": "tier1_bin"
|
||||
},
|
||||
{
|
||||
"name": "sha256sum",
|
||||
"tier": "tier1_bin"
|
||||
},
|
||||
{
|
||||
"name": "sha384sum",
|
||||
"tier": "tier1_bin"
|
||||
},
|
||||
{
|
||||
"name": "sha512sum",
|
||||
"tier": "tier1_bin"
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -37,18 +37,18 @@
|
||||
"protomux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePath.js",
|
||||
"keys": [
|
||||
"barePath"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareEncoding.js",
|
||||
"keys": [
|
||||
"bareEncoding"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePath.js",
|
||||
"keys": [
|
||||
"barePath"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareEvents.js",
|
||||
"keys": [
|
||||
@@ -61,12 +61,6 @@
|
||||
"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,27 +86,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/fetch.js",
|
||||
"path": "/lib/bare/bundles/bareReadline.js",
|
||||
"keys": [
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAsyncHooks.js",
|
||||
"keys": [
|
||||
"bareAsyncHooks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAssert.js",
|
||||
"keys": [
|
||||
"bareAssert"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAtomics.js",
|
||||
"keys": [
|
||||
"bareAtomics"
|
||||
"bareReadline"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -122,9 +98,27 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareApk.js",
|
||||
"path": "/lib/bare/bundles/bareAsyncHooks.js",
|
||||
"keys": [
|
||||
"bareApk"
|
||||
"bareAsyncHooks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAtomics.js",
|
||||
"keys": [
|
||||
"bareAtomics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAssert.js",
|
||||
"keys": [
|
||||
"bareAssert"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/fetch.js",
|
||||
"keys": [
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -133,24 +127,30 @@
|
||||
"bareBmp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareApk.js",
|
||||
"keys": [
|
||||
"bareApk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundle.js",
|
||||
"keys": [
|
||||
"bareBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleCompile.js",
|
||||
"keys": [
|
||||
"bareBundleCompile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBuffer.js",
|
||||
"keys": [
|
||||
"bareBuffer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleCompile.js",
|
||||
"keys": [
|
||||
"bareBundleCompile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBluetoothApple.js",
|
||||
"keys": [
|
||||
@@ -187,18 +187,18 @@
|
||||
"bareBundleId"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDebugLog.js",
|
||||
"keys": [
|
||||
"bareDebugLog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDelta.js",
|
||||
"keys": [
|
||||
"bareDelta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDebugLog.js",
|
||||
"keys": [
|
||||
"bareDebugLog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDiagnosticsChannel.js",
|
||||
"keys": [
|
||||
@@ -223,12 +223,6 @@
|
||||
"bareDaemon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDgram.js",
|
||||
"keys": [
|
||||
"bareDgram"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareExif.js",
|
||||
"keys": [
|
||||
@@ -241,24 +235,18 @@
|
||||
"bareEnv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDgram.js",
|
||||
"keys": [
|
||||
"bareDgram"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpeg.js",
|
||||
"keys": [
|
||||
"bareFfmpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFormat.js",
|
||||
"keys": [
|
||||
"bareFormat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFormData.js",
|
||||
"keys": [
|
||||
"bareFormData"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFfmpegEncodings.js",
|
||||
"keys": [
|
||||
@@ -266,21 +254,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareGif.js",
|
||||
"path": "/lib/bare/bundles/bareFormData.js",
|
||||
"keys": [
|
||||
"bareGif"
|
||||
"bareFormData"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHeif.js",
|
||||
"path": "/lib/bare/bundles/bareFormat.js",
|
||||
"keys": [
|
||||
"bareHeif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareGtk.js",
|
||||
"keys": [
|
||||
"bareGtk"
|
||||
"bareFormat"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -290,9 +272,21 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFs.js",
|
||||
"path": "/lib/bare/bundles/bareGif.js",
|
||||
"keys": [
|
||||
"bareFs"
|
||||
"bareGif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareGtk.js",
|
||||
"keys": [
|
||||
"bareGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHeif.js",
|
||||
"keys": [
|
||||
"bareHeif"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -307,6 +301,12 @@
|
||||
"bareHttpParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFs.js",
|
||||
"keys": [
|
||||
"bareFs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIco.js",
|
||||
"keys": [
|
||||
@@ -325,18 +325,18 @@
|
||||
"bareInspect"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttps.js",
|
||||
"keys": [
|
||||
"bareHttps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttp1.js",
|
||||
"keys": [
|
||||
"bareHttp1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttps.js",
|
||||
"keys": [
|
||||
"bareHttps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"keys": [
|
||||
@@ -379,18 +379,6 @@
|
||||
"bareLink"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"keys": [
|
||||
"bareMake"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModule.js",
|
||||
"keys": [
|
||||
"bareModule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModuleResolve.js",
|
||||
"keys": [
|
||||
@@ -404,9 +392,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"path": "/lib/bare/bundles/bareModule.js",
|
||||
"keys": [
|
||||
"bareDev"
|
||||
"bareModule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"keys": [
|
||||
"bareMake"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -427,6 +421,12 @@
|
||||
"bareMedia"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNodeFetch.js",
|
||||
"keys": [
|
||||
"bareNodeFetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNet.js",
|
||||
"keys": [
|
||||
@@ -440,9 +440,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNodeFetch.js",
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"keys": [
|
||||
"bareNodeFetch"
|
||||
"bareDev"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -476,9 +476,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePackDrive.js",
|
||||
"path": "/lib/bare/bundles/barePack.js",
|
||||
"keys": [
|
||||
"barePackDrive"
|
||||
"barePack"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -488,15 +488,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePunycode.js",
|
||||
"path": "/lib/bare/bundles/barePackDrive.js",
|
||||
"keys": [
|
||||
"barePunycode"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePack.js",
|
||||
"keys": [
|
||||
"barePack"
|
||||
"barePackDrive"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -512,9 +506,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"path": "/lib/bare/bundles/barePunycode.js",
|
||||
"keys": [
|
||||
"bareProcess"
|
||||
"barePunycode"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -536,9 +530,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePromClient.js",
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"keys": [
|
||||
"barePromClient"
|
||||
"bareProcess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRpc.js",
|
||||
"keys": [
|
||||
"bareRpc"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -548,15 +548,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSemver.js",
|
||||
"path": "/lib/bare/bundles/barePromClient.js",
|
||||
"keys": [
|
||||
"bareSemver"
|
||||
"barePromClient"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRpc.js",
|
||||
"path": "/lib/bare/bundles/bareSemver.js",
|
||||
"keys": [
|
||||
"bareRpc"
|
||||
"bareSemver"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -571,12 +571,6 @@
|
||||
"bareRepl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStdio.js",
|
||||
"keys": [
|
||||
"bareStdio"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRun.js",
|
||||
"keys": [
|
||||
@@ -608,9 +602,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStorage.js",
|
||||
"path": "/lib/bare/bundles/bareStdio.js",
|
||||
"keys": [
|
||||
"bareStorage"
|
||||
"bareStdio"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -631,6 +625,12 @@
|
||||
"bareSubprocess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStorage.js",
|
||||
"keys": [
|
||||
"bareStorage"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTap.js",
|
||||
"keys": [
|
||||
@@ -674,9 +674,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTty.js",
|
||||
"path": "/lib/bare/bundles/bareUiKit.js",
|
||||
"keys": [
|
||||
"bareTty"
|
||||
"bareUiKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -686,15 +686,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUiKit.js",
|
||||
"path": "/lib/bare/bundles/bareTty.js",
|
||||
"keys": [
|
||||
"bareUiKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnpack.js",
|
||||
"keys": [
|
||||
"bareUnpack"
|
||||
"bareTty"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -710,9 +704,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKit.js",
|
||||
"path": "/lib/bare/bundles/bareUnpack.js",
|
||||
"keys": [
|
||||
"bareWebKit"
|
||||
"bareUnpack"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -721,6 +715,18 @@
|
||||
"bareWalkHandles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebp.js",
|
||||
"keys": [
|
||||
"bareWebp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKit.js",
|
||||
"keys": [
|
||||
"bareWebKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKitGtk.js",
|
||||
"keys": [
|
||||
@@ -734,9 +740,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebp.js",
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"keys": [
|
||||
"bareWebp"
|
||||
"bareV8ToIstanbul"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -751,24 +757,12 @@
|
||||
"bareWinUi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"keys": [
|
||||
"bareV8ToIstanbul"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareXdiff.js",
|
||||
"keys": [
|
||||
"bareXdiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWhich.js",
|
||||
"keys": [
|
||||
"bareWhich"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareZlib.js",
|
||||
"keys": [
|
||||
@@ -776,9 +770,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareZmq.js",
|
||||
"path": "/lib/bare/bundles/bareWhich.js",
|
||||
"keys": [
|
||||
"bareZmq"
|
||||
"bareWhich"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWorker.js",
|
||||
"keys": [
|
||||
"bareWorker"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -788,9 +788,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWorker.js",
|
||||
"path": "/lib/bare/bundles/bareZmq.js",
|
||||
"keys": [
|
||||
"bareWorker"
|
||||
"bareZmq"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1607,9 +1607,9 @@
|
||||
],
|
||||
"bundleProvenance": {
|
||||
"schemaVersion": 1,
|
||||
"generatedAt": "2026-04-09T23:33:39.947Z",
|
||||
"gitCommit": "3a6990604607b059feaf78006337e3845dc762c7",
|
||||
"nodeVersion": "v22.22.0",
|
||||
"generatedAt": "2026-04-21T21:25:45.989Z",
|
||||
"gitCommit": "c50bee46ebd5f05189131385330d077c2332817c",
|
||||
"nodeVersion": "v20.20.2",
|
||||
"bundleTier": "all",
|
||||
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
|
||||
"buildScript": "packages/bare-os-bare-libs/build.mjs"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"atMs": 1775777169246,
|
||||
"atMs": 1776806744827,
|
||||
"commands": [
|
||||
"arch",
|
||||
"awk",
|
||||
@@ -111,7 +111,9 @@
|
||||
"setfacl",
|
||||
"sh",
|
||||
"sha1sum",
|
||||
"sha224sum",
|
||||
"sha256sum",
|
||||
"sha384sum",
|
||||
"sha512sum",
|
||||
"shuf",
|
||||
"sleep",
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user