Host API
The building blocks in @blaiseagent/runner/host for plugs that provide a host.
@blaiseagent/runner/host exports what a plug needs to provide a host. The Host type itself,
which plugs receive as ctx.host, is described in the Plug API.
createHost(options)
Builds a lazy Host.
| Option | Type | Description |
|---|---|---|
info | HostInfo | Kind, OS, home, temporary directory, workspace and persistent. |
connect | () => Promise<HostConnection> | Creates or wakes the machine and connects. Runs once, on first use. |
Concurrent first uses share one connect call. exec and spawn run over the connection's
transport, and fs is the node:vfs API over its provider. When info.persistent is true, spawn
starts the process under the watchdog unless its transport already owns supervision. SSH transports
manage their own process groups and wait for remote termination before reporting exit. After the
runner closes the host, any further use rejects.
HostConnection
What connect returns.
| Field | Required | Description |
|---|---|---|
transport | yes | spawn(argv, { cwd, env }) returns a HostProcess: stdin, stdout, stderr, exited, kill. |
fs | no | An async VirtualProvider. The default is ExecProvider over transport. |
forward | no | Port forwarding for ForwardSpec values. Without it, host.forward rejects. |
sync | no | A WorkerConnectSpec that enables the synchronous fs methods. |
close | yes | Called by the runner when the host is no longer needed. |
The synchronous file system
Remote providers are async. When a connection has sync, a worker thread opens its own connection
and the calling thread waits for it, so readFileSync and the rest work.
WorkerConnectSpec field | Description |
|---|---|
module | A file: URL the worker imports. |
exportName | An exported function that takes args and resolves with a SyncConnection. |
args | Plain data that can be copied to the worker. It is not shared with the main thread. |
A SyncConnection has an fs provider and an optional close(). Without sync, the synchronous
methods throw ENOTSUP. File descriptors (openSync) are never available on remote hosts.
The first synchronous call starts the worker, which connects before it answers. Later calls cost one
round trip. The bridge works on Bun. A call that gets no answer within 30 seconds fails with
ETIMEDOUT.
wrapHost(base, wrap)
A host that runs every process of base through wrap, for example under an OS sandbox. wrap
receives the argv with the working directory and environment and returns the new argv and
environment. fs, info and forward are the base host's, and closing is still the base host's
plug's job.
ExecProvider
A file system provider for any host that can run POSIX tools. Every operation is a small command
over transport.spawn. It supports the async API only, and needs uname, stat, ls, mkdir,
rmdir, rm, mv, cp, cat, test, ln, readlink and realpath on the machine.
SSH
| Export | Description |
|---|---|
sshConnect(stream, auth) | SSH over any byte stream, with keepalives. auth has username, privateKey and an optional hostKey fingerprint. |
SshConnection | transport, sftp(), forward(spec), and Symbol.asyncDispose to disconnect. |
SftpProvider | The provider behind sftp(). |
generateSessionKey() | A new ed25519 key pair in OpenSSH format, for access that lasts one session. |
hostKey is the fingerprint in the format ssh-keygen -lf prints (SHA256:…). It is checked
before anything else is sent. Omit it only when the stream is already authenticated end to end.
Commands run as one remote shell command line: cd to the working directory, export each
environment variable (names must be valid shell names), then exec the command with every word
quoted.
Byte streams
| Export | Description |
|---|---|
tcpStream(host, port) | A TCP connection as a ByteStream. Rejects if it cannot connect. |
webSocketStream(url, options) | A WebSocket as a ByteStream; binary messages are the bytes. options.headers sets request headers. |
A ByteStream is a readable and a writable of Uint8Array chunks.
Testing
@blaiseagent/runner/testing exports startSshServer(), an SSH server on a loopback port for
tests. It accepts one generated key, runs exec requests with /bin/sh -c on the local machine,
serves SFTP over the local file system, and supports both directions of port forwarding. The result
has host, port, hostKey (the fingerprint to pin), clientKey and close().
Tests of the synchronous bridge must run the server in another process, because the calling thread is blocked while it waits.