Files
bare-operating-system/packages/bare-os-booter/lib/shell/shell-pipeline.js
T
2026-08-18 18:11:28 -04:00

65 lines
2.1 KiB
JavaScript

/**
* Pipeline child-ctx clone, raw-chunk capture, and optional stage timeout.
*/
/**
* Shallow clone for pipeline **`/bin`** execution: session **`env`**, optional **`shellStdin`**, and
* **`bareOsStdoutCaptured`** when stdout is captured (pipe to next stage or **`>`** redirect) so
* utilities (e.g. **`ls`**) can use one-record-per-line output.
* @param {Record<string, unknown>} ctx
* @param {Record<string, string>} env
* @param {string | null} stdinText
* @param {boolean} bareOsStdoutCaptured
*/
export function bareOsPipelineChildCtx(ctx, env, stdinText, bareOsStdoutCaptured) {
const o = Object.assign({}, ctx, {
env: env && typeof env === 'object' ? { ...env } : env,
bareOsStdoutCaptured
})
if (stdinText != null) o.shellStdin = stdinText
return o
}
/**
* Convert raw binary chunks into shell pipeline capture text.
* Pipeline transport is text-based, so bytes are mapped 1:1 via char codes.
* @param {string | Uint8Array} chunk
*/
export function bareOsPipelineRawChunkToText(chunk) {
if (typeof chunk === 'string') return chunk
if (!(chunk instanceof Uint8Array)) return String(chunk)
let s = ''
for (let i = 0; i < chunk.length; i++) s += String.fromCharCode(chunk[i])
return s
}
/**
* Optional timeout guard for potentially stalled pipeline stages.
* @param {Record<string, string>} env
* @param {() => Promise<unknown>} run
* @param {string} label
*/
export async function runWithShellPipelineStageTimeout(env, run, label) {
const raw = Number.parseInt(String(env.BARE_OS_SHELL_PIPELINE_STAGE_TIMEOUT_MS || ''), 10)
const timeoutMs = Number.isFinite(raw) && raw > 0 ? Math.min(raw, 120000) : 0
if (!timeoutMs) return await run()
/** @type {ReturnType<typeof setTimeout> | null} */
let timer = null
try {
return await Promise.race([
run(),
new Promise((_, reject) => {
timer = setTimeout(() => {
reject(
new Error(
`shell: pipeline stage timeout (${timeoutMs}ms): ${label}`
)
)
}, timeoutMs)
})
])
} finally {
if (timer) clearTimeout(timer)
}
}