Core launcher implementation used by outer start-runner entry. It owns env parsing, verser2 transport bootstrap, runtime selection/switching, child spawn orchestration, child/host channel plumbing, and the runtime-agnostic inner runner engine (Runner class, RunnerAppContext, InputStream parsing, LocalStorageAgent, MessageUtils) consumed by runner-node.
- Boundary module decomposition:
bin/start-runner.ts: CLI/bootstrap flow with verser2 transport init.transport/: verser2 runner transport, config parsing, local channel bridge.executor/*: spawn strategies, stdio contracts, entry resolvers, lifecycle helpers.runner.ts: runtime-agnostic sequence execution engine (Runner<X>class) — loads sequence, createsAppContext, wires input/output/control/monitoring streams, handles KILL/STOP/MONITORING_RATE/PONG/STORAGE/EVENT control messages.runner-app-context.ts:RunnerAppContextimplementingAppContextwith v1/v2 hub/space clients,APIExpose,ILocalStorage,EventEmitter, monitoring writer, lifecycle handler registries.input-stream.ts: input stream header parsing (readInputStreamHeaders) andDataStreammapping (mapToInputDataStream).message-utils.ts: staticwriteMessageOnStream([code, data], stream)helper.local-storage-agent.ts:ILocalStorageimplementation with promise-based STORAGE_UPDATE ack via monitoring frames.
- Verser2 transport as default: host connectivity now uses
RunnerVerser2Transportwith HTTP-based channel routing; the legacyHostClientdirect-socket approach is preserved in runner-node. - Local channel bridge:
LocalChannelServerlistens on127.0.0.1:0and accepts runtime wrapper connections via a 37-byte header protocol (instance ID + channel index), enabling the inner runner to open its semantic channels. - Strict channel contract: child processes are started with 6-slot stdio and only channels 0–2 and 4–5 are actively used for runtime transport.
- Validation-first startup: malformed adapter env/paths/ports are rejected before process launch.
start-runner.ts composes:
parseRunnerTransportConfig(instanceId)readsSCRAMJET_RUNNER_TRANSPORT_CONFIG(JSON, kind: "verser2").RunnerVerser2Transport.init()starts local channel server + verser2 guest, connects to host.- Boot config JSON written with
verser2Runtimeblock for inner runtime. selectExecutor(engines)-> resolver/launcher -> executor spawn.- Bidirectional pipe setup: verser2 routes <-> child fds with lifecycle observation.
- On child close:
translateChildClose, terminal frame fallback, transport disconnect, cleanup.
Inner runner flow (Runner.main() / Runner.runSequence()):
premain()connects to host, sets up streams, sends PING handshake.initAppContext(config)createsRunnerAppContextwith v1/v2 clients, localStorage agent,RunnerProxy.- Loads sequence module via
require(), validates exported functions. runSequence()iterates sequence functions, pipesinputDataStreamthrough each, last output → host output.- Control stream dispatches STOP/KILL/EVENT/STORAGE_UPDATE; on exit calls
cleanup(),exit().
- Uses
@scramjet/types/@scramjet/symbolscontracts and runtime wrappers (runner-node,runner-bun,runner-python). - Uses
@scramjet/rest-api2for v2HubClient/SpaceClientinRunnerAppContext. - Uses
@signicode/verser2-guest-nodefor verser2 guest connectivity andLocalChannelServerfor local channel bridge. - Uses Node process primitives (
child_process.spawn,stream,fs,net). - Inner
Runnerclass re-exported viaindex.tsforrunner-nodeconsumption.