import { createRnxCommandInvocation, getRnxCommandAvailability, getRnxFirstPositional, } from './command-registry' import { renderRnxHelp } from './help-core' import { resolveHiddenRuntimeAlias } from './hidden-runtime-alias' import { parseRnxArgs } from './parse-args' import type { CommandArtifact, CommandExecutionResult, CommandWriter, RunRnxCoreOptions, SemanticInvocation, } from './command-contract' interface CapturedCommandWriter { writer: CommandWriter stdout: string[] stderr: string[] } function createCapturedWriter(writer?: CommandWriter): CapturedCommandWriter { const stdout: string[] = [] const stderr: string[] = [] return { stdout, stderr, writer: { stdout(text) { stdout.push(text) writer?.stdout(text) }, stderr(text) { stderr.push(text) writer?.stderr(text) }, }, } } function result( captured: CapturedCommandWriter, exitCode: number, invocations: SemanticInvocation[] = [], artifacts: CommandArtifact[] = [], ): CommandExecutionResult { return { exitCode, stdout: captured.stdout.join(''), stderr: captured.stderr.join(''), invocations, artifacts, } } export async function runRnxCore( argv: string[], options: RunRnxCoreOptions, ): Promise { const captured = createCapturedWriter(options.writer) const signal = options.signal ?? new AbortController().signal let parsed = parseRnxArgs(argv) for (const warning of parsed.warnings) captured.writer.stderr(`${warning}\n`) if (!parsed.command && parsed.commandArgs.length > 0) { parsed = resolveHiddenRuntimeAlias(parsed) } if (parsed.version) { captured.writer.stderr( 'rnx --version is unavailable in the browser backend; use the node backend.\n', ) return result(captured, 1) } if (!parsed.command) { if (parsed.commandArgs.length > 0) { const attempted = getRnxFirstPositional(parsed.commandArgs) ?? parsed.commandArgs[0] captured.writer.stderr(`unknown command: ${attempted}\n`) return result(captured, 1) } captured.writer.stdout(`${renderRnxHelp({ backend: options.backend.kind })}\n`) return result(captured, 0) } const command = parsed.command const helpRequested = parsed.help || parsed.commandArgs.includes('--help') || parsed.commandArgs.includes('-h') if (helpRequested) { const grouping = new Set(['do', 'get', 'debug', 'wait']) const subVerb = getRnxFirstPositional(parsed.commandArgs) captured.writer.stdout( `${renderRnxHelp({ backend: options.backend.kind, command, commandArgs: parsed.commandArgs, prefer: grouping.has(command) && subVerb ? 'verb' : undefined, group: grouping.has(command) ? command : undefined, })}\n`, ) return result(captured, 0) } const availability = getRnxCommandAvailability( command, parsed.commandArgs, options.backend.kind, ) if (!availability.available) { captured.writer.stderr(`${availability.reason ?? `rnx ${command} is unavailable`}\n`) return result(captured, 1) } if (signal.aborted) { captured.writer.stderr('rnx: command cancelled\n') return result(captured, 1) } const invocation = createRnxCommandInvocation({ command, args: parsed.commandArgs, globalFlags: parsed.globalFlags, }) try { const execution = await options.backend.execute(invocation, { writer: captured.writer, signal, }) return result( captured, execution.exitCode, execution.invocations, execution.artifacts, ) } catch (error) { const message = signal.aborted ? 'command cancelled' : error instanceof Error ? error.message : String(error) captured.writer.stderr(`rnx: ${message}\n`) return result(captured, 1) } }