250 lines
6.5 KiB
JavaScript
250 lines
6.5 KiB
JavaScript
/**
|
|
* Host-bridge CLI delegates: hrpc, bundlebee staging hints, sidecar caps, pear-runtime matrix.
|
|
* Stock booter provides audit/probe paths; hosts replace ctx methods or set env flags (see each command).
|
|
*/
|
|
|
|
/** @param {Record<string, unknown>} ctx */
|
|
function env(ctx) {
|
|
return ctx.vfs?.env || {}
|
|
}
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {string} name
|
|
*/
|
|
function hostCap(ctx, name) {
|
|
if (typeof ctx.bareOsHostCapability === 'function') {
|
|
try {
|
|
return !!ctx.bareOsHostCapability(name)
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* @param {unknown} fn
|
|
* @returns {boolean}
|
|
*/
|
|
export function isStockHrpcRequest(fn) {
|
|
return (
|
|
typeof fn === 'function' &&
|
|
Object.prototype.hasOwnProperty.call(fn, '__bareOsStockHrpcRequest')
|
|
)
|
|
}
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {string[]} argv
|
|
*/
|
|
export async function runHrpcCli(ctx, argv) {
|
|
const args = argv.slice(1).filter((a) => a !== '--')
|
|
if (
|
|
args.length === 0 ||
|
|
args[0] === '-h' ||
|
|
args[0] === '-help' ||
|
|
args[0] === '--help'
|
|
) {
|
|
ctx.console.log(
|
|
'usage: hrpc probe\n' +
|
|
' hrpc request <service> <method> [json]\n' +
|
|
'Bare OS: uses ctx.bareOsHrpcRequest (stock routes + optional host override via BARE_OS_HRPC_BRIDGE_WIRED) ' +
|
|
'or prints allowlist probe.\n'
|
|
)
|
|
return
|
|
}
|
|
if (args[0] === 'probe') {
|
|
const probe =
|
|
typeof ctx.bareOsHrpcAllowlistProbe === 'function'
|
|
? ctx.bareOsHrpcAllowlistProbe()
|
|
: { note: 'bareOsHrpcAllowlistProbe unavailable' }
|
|
ctx.console.log(JSON.stringify(probe, null, 2))
|
|
return
|
|
}
|
|
if (args[0] !== 'request') {
|
|
ctx.console.error('hrpc: unknown subcommand (try: hrpc probe | hrpc request ...)')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
const service = args[1]
|
|
const method = args[2]
|
|
if (!service || !method) {
|
|
ctx.console.error('usage: hrpc request <service> <method> [json]')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
let payload = {}
|
|
const jsonPart = args.slice(3).join(' ').trim()
|
|
if (jsonPart) {
|
|
try {
|
|
payload = JSON.parse(jsonPart)
|
|
} catch {
|
|
ctx.console.error('hrpc: invalid JSON payload')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
}
|
|
const req = ctx.bareOsHrpcRequest
|
|
if (typeof req !== 'function') {
|
|
ctx.console.error('hrpc: ctx.bareOsHrpcRequest unavailable')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
if (isStockHrpcRequest(req) && hostCap(ctx, 'hrpcBridge')) {
|
|
ctx.console.error(
|
|
'hrpc: host bridge capability is advertised, but stock handler is still active; host override was not installed.'
|
|
)
|
|
}
|
|
try {
|
|
const out = await req.call(ctx, service, method, payload)
|
|
if (out !== undefined) ctx.console.log(JSON.stringify(out, null, 2))
|
|
} catch (e) {
|
|
ctx.console.error(e?.message || String(e))
|
|
ctx.exitCode = 1
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {string[]} argv
|
|
*/
|
|
export async function runBundlebeeCli(ctx, argv) {
|
|
const args = argv.slice(1).filter((a) => a !== '--')
|
|
if (
|
|
args.length === 0 ||
|
|
args[0] === '-h' ||
|
|
args[0] === '-help' ||
|
|
args[0] === '--help'
|
|
) {
|
|
ctx.console.log(
|
|
'usage: bundlebee hint [label]\n' +
|
|
' bundlebee status\n' +
|
|
'Emits process event bare-os:bundlebee-cli and prints BARE_OS_BUNDLEBEE_STAGE_JSON when set.\n'
|
|
)
|
|
return
|
|
}
|
|
if (args[0] === 'status') {
|
|
const raw = String(env(ctx).BARE_OS_BUNDLEBEE_STAGE_JSON || '').trim()
|
|
if (!raw) {
|
|
ctx.console.log(
|
|
JSON.stringify({
|
|
ok: false,
|
|
note: 'BARE_OS_BUNDLEBEE_STAGE_JSON unset; host may populate after pear stage.'
|
|
})
|
|
)
|
|
return
|
|
}
|
|
try {
|
|
ctx.console.log(JSON.stringify(JSON.parse(raw), null, 2))
|
|
} catch {
|
|
ctx.console.error('bundlebee: invalid BARE_OS_BUNDLEBEE_STAGE_JSON')
|
|
ctx.exitCode = 1
|
|
}
|
|
return
|
|
}
|
|
if (args[0] === 'hint') {
|
|
const label = args.slice(1).join(' ').trim() || 'default'
|
|
if (typeof globalThis.process?.emit === 'function') {
|
|
try {
|
|
globalThis.process.emit('bare-os:bundlebee-cli', {
|
|
label: label.slice(0, 256),
|
|
argv: argv.slice(0, 16),
|
|
ts: Date.now()
|
|
})
|
|
} catch (e) {
|
|
ctx.console.error('bundlebee: emit failed: ' + (e?.message || e))
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
}
|
|
ctx.console.log(
|
|
JSON.stringify({
|
|
ok: true,
|
|
emitted: 'bare-os:bundlebee-cli',
|
|
label
|
|
})
|
|
)
|
|
return
|
|
}
|
|
ctx.console.error('bundlebee: unknown subcommand')
|
|
ctx.exitCode = 1
|
|
}
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {string[]} argv
|
|
*/
|
|
export async function runSidecarCli(ctx, argv) {
|
|
const args = argv.slice(1).filter((a) => a !== '--')
|
|
if (
|
|
args.length === 0 ||
|
|
args[0] === '-h' ||
|
|
args[0] === '-help' ||
|
|
args[0] === '--help'
|
|
) {
|
|
ctx.console.log(
|
|
'usage: sidecar cap <class>\n' +
|
|
'Calls ctx.bareOsSidecarResourceCap (emits bare-os:sidecar-resource-cap). ' +
|
|
'Set BARE_OS_SIDECAR_BRIDGE_WIRED=1 when a host listener consumes sidecar events.\n'
|
|
)
|
|
return
|
|
}
|
|
if (args[0] === 'cap' && args[1]) {
|
|
const fn = ctx.bareOsSidecarResourceCap
|
|
if (typeof fn !== 'function') {
|
|
ctx.console.error('sidecar: ctx.bareOsSidecarResourceCap missing')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
try {
|
|
const ok = await fn.call(ctx, { capClass: String(args[1]).slice(0, 128) })
|
|
ctx.console.log(
|
|
JSON.stringify({
|
|
ok: !!ok,
|
|
capClass: args[1],
|
|
hostListenerExpected: hostCap(ctx, 'sidecarBridge')
|
|
})
|
|
)
|
|
} catch (e) {
|
|
ctx.console.error(e?.message || String(e))
|
|
ctx.exitCode = 1
|
|
}
|
|
return
|
|
}
|
|
ctx.console.error('sidecar: usage: sidecar cap <class>')
|
|
ctx.exitCode = 1
|
|
}
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {string[]} argv
|
|
*/
|
|
export async function runPearRuntimeMatrixCli(ctx, argv) {
|
|
const args = argv.slice(1).filter((a) => a !== '--')
|
|
if (
|
|
args.includes('-h') ||
|
|
args.includes('--help') ||
|
|
args[0] === '-help'
|
|
) {
|
|
ctx.console.log(
|
|
'usage: pear-runtime-matrix\n' +
|
|
'Prints JSON from ctx.bareOsPearRuntimeMatrixProbe() (merges BARE_OS_PEAR_RUNTIME_MATRIX_JSON when set).\n'
|
|
)
|
|
return
|
|
}
|
|
const fn = ctx.bareOsPearRuntimeMatrixProbe
|
|
if (typeof fn !== 'function') {
|
|
ctx.console.error('pear-runtime-matrix: probe unavailable')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
try {
|
|
const out = fn.call(ctx)
|
|
ctx.console.log(JSON.stringify(out, null, 2))
|
|
} catch (e) {
|
|
ctx.console.error(e?.message || String(e))
|
|
ctx.exitCode = 1
|
|
}
|
|
}
|