/** * 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} ctx */ function env(ctx) { return ctx.vfs?.env || {} } /** * @param {Record} 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} 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 [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 [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} 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} 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 \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 ') ctx.exitCode = 1 } /** * @param {Record} 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 } }