import { rnxExit } from '../run-rnx' import { callInBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge' export type ShellBooleanModeAction = 'on' | 'off' | 'toggle' export interface ShellBooleanModeOptions { port?: number verbose?: boolean } export interface ShellBooleanModeConfig { modeKey: string displayName: string actionId: string } export interface ShellBooleanModeResult { current: boolean target: boolean changed: boolean } export function parseShellBooleanModeAction(args: string[]): ShellBooleanModeAction { const action = args[0]?.toLowerCase() ?? 'toggle' if (action !== 'on' && action !== 'off' && action !== 'toggle') { console.error(` unknown argument: "${action}" (expected on | off | toggle)`) rnxExit(1) } return action } export async function runShellBooleanMode( args: string[], opts: ShellBooleanModeOptions, config: ShellBooleanModeConfig, ): Promise { const parsed = parseBridgeCliArgs(args, { port: opts.port }) const action = parseShellBooleanModeAction(parsed.positional) const bridge = createBridgeFromParsed({ ...parsed, commandTimeoutMs: 5000 }) try { const settings = await callInBridge>( bridge, 'SootSim.bridges.settings.get', ) const current = Boolean(settings?.[config.modeKey]) const target = action === 'on' ? true : action === 'off' ? false : !current if (current === target) { console.log(` ${config.displayName}: already ${target ? 'on' : 'off'}`) return { current, target, changed: false } } const changed = await bridge.send({ type: 'evaluate', acquireLock: true, code: `(async () => { const modeKey = ${JSON.stringify(config.modeKey)} const target = ${JSON.stringify(target)} window.dispatchEvent(new CustomEvent('sootsim:shell-command', { detail: { type: 'fire-action', id: ${JSON.stringify(config.actionId)} }, })) const deadline = Date.now() + 1200 while (Date.now() < deadline) { if (Boolean(window.SootSim?.bridges?.settings?.get?.()?.[modeKey]) === target) { return true } await new Promise((resolve) => setTimeout(resolve, 40)) } return false })()`, }) if (!changed) { throw new Error( `${config.displayName} did not change to ${target ? 'on' : 'off'}; the live shell may not support this mode`, ) } console.log( ` ${config.displayName}: ${current ? 'on' : 'off'} -> ${target ? 'on' : 'off'}`, ) return { current, target, changed: true } } finally { bridge.close() } }