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:
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user