167 lines
8.8 KiB
Markdown
167 lines
8.8 KiB
Markdown
# Runa VS Code client
|
|
|
|
This is a development client for a trusted localhost Runa image. It uses
|
|
the [version 4 protocol](../docs/protocol.md) over WebSockets with the `runa-debug`
|
|
subprotocol, not Rust APIs, and never
|
|
hosts actors or starts its own image.
|
|
|
|
## Run from source
|
|
|
|
Requirements: VS Code 1.96+, Node.js 22+, npm, and the repository's Rust toolchain.
|
|
|
|
From the repository root:
|
|
|
|
```sh
|
|
npm --prefix vscode ci
|
|
mise run start
|
|
```
|
|
|
|
Open the repository in VS Code. In Run and Debug, select **Run Runa Extension**
|
|
and press F5. The launch task compiles TypeScript before opening an Extension
|
|
Development Host.
|
|
|
|
In that host:
|
|
|
|
1. Run **Runa: Connect to Local Image**. The default is `127.0.0.1:3737`;
|
|
`runa.address` changes the suggested endpoint.
|
|
2. The **Runa Image Sources** Explorer view automatically shows the image's
|
|
`source` directory (see [Image source files](#image-source-files)).
|
|
Right-click a `.rn` file and choose **Spawn** (initial state `null`) or
|
|
**Spawn with State...** (enter JSON in the input field, for example `0` for
|
|
`actors/counter`). **Runa: Spawn Actor** in **Runa Actors** prompts for a source
|
|
path and state. The command reports and returns the new actor reference.
|
|
Mailbox capacity is 64.
|
|
3. Click an actor or run **Runa: Inspect Actor** to open its JSON snapshot.
|
|
4. Right-click an actor to send a JSON message or a system message: pause,
|
|
resume, stop, kill, restart, reload, or become another source path. These
|
|
actions are also available in the Command Palette with an actor picker.
|
|
5. Use **Runa: Advance Scheduler** to execute an explicit number of ticks
|
|
(instruction budget 32 per actor). Send only queues a message; it does not
|
|
execute it. For the counter, send `{"op":"add","value":7}`, then advance.
|
|
6. Run **Runa: Disconnect** to close only this client connection.
|
|
|
|
JSON input supports null, booleans, signed 64-bit integers, strings, arrays,
|
|
and objects. Floats and out-of-range integers are rejected rather than rounded.
|
|
Use `{"$actor":"@<21-character-reference>"}` for a typed actor reference and
|
|
`{"$record":{"$actor":"literal"}}` to escape a marker-shaped object.
|
|
REPL-local names are not shared with the extension. Input uses the same
|
|
depth/node/string limits as the runtime; the full wire request must also fit
|
|
1 MiB. Cancelling a prompt sends no mutation. Changing connections during a
|
|
prompt rejects the action instead of applying it to the new image.
|
|
|
|
Connection prompts accept numeric IPv4 loopback addresses (`127.x.x.x`) or
|
|
`[::1]:port`. DNS names, wildcard addresses, remote addresses, and IPv4-mapped
|
|
IPv6 addresses are rejected. There is no authentication: connect only to a
|
|
trusted local server. In a remote VS Code window, localhost refers to the
|
|
machine running the extension host, not necessarily the desktop.
|
|
|
|
## Snapshot semantics
|
|
|
|
- The tree shows actor references, lifecycle status, and queued/reserved counts.
|
|
Tooltips include implementation ID, incarnation, and failure text.
|
|
- Inspect fetches a fresh snapshot through `inspect_actor`. Documents show
|
|
committed state, FIFO queued messages, the reserved message, status, and
|
|
active-execution telemetry. Tagged values distinguish actor references from
|
|
strings and preserve signed 64-bit integers exactly.
|
|
- Documents are read-only snapshots, not editable actor state or live VM frames.
|
|
The timestamp records when this client received the data, not a runtime clock.
|
|
Server `image_changed` notifications automatically update the tree and open
|
|
documents. Bursts are coalesced, and changes arriving during a fetch trigger
|
|
a follow-up fetch. **Refresh Image** is also available on demand.
|
|
- Open documents are retained and marked `connected: false` on disconnect.
|
|
- Explicit disconnect, reconnect, and extension deactivation complete the
|
|
WebSocket close handshake. Deactivation waits for outstanding closes; an
|
|
unresponsive peer is forcibly disconnected after five seconds. Protocol
|
|
corruption and request failures still terminate the connection without retry.
|
|
Each connection gets distinct document URIs; reconnecting never replaces
|
|
snapshots from an earlier connection or another image. Closing a document
|
|
releases its cache; snapshots are not persisted across VS Code restarts.
|
|
- There is no auto-connect, polling, automatic reconnect, or request retry.
|
|
Timeout, peer disconnect, malformed data, and version/correlation failures
|
|
invalidate the connection and are surfaced in a notification and the **Runa**
|
|
output channel. Server-reported operation errors leave the connection usable.
|
|
- The client never ticks the scheduler implicitly or drains `get_events`.
|
|
Notifications are non-destructive invalidations, not a replayable runtime
|
|
event stream; reconnect fetches the current image rather than replaying history.
|
|
|
|
For automation, the `runa.connect` command also accepts an explicit endpoint
|
|
string, and `runa.inspect` accepts an object with an `actor_ref` field.
|
|
`runa.spawn` accepts `{ path: string, state: string }`, where state is
|
|
natural JSON text, and resolves to the new reference. `runa.spawnSource` and
|
|
`runa.spawnSourceWithState` accept a source file URI (the latter also optional
|
|
JSON state text). `runa.send` accepts `{ actor_ref: string }` and JSON message
|
|
text. `runa.pause`, `runa.resume`, `runa.stop`, `runa.kill`, `runa.restart`, and
|
|
`runa.reload` accept `{ actor_ref: string }`; `runa.become` also accepts a
|
|
target source path.
|
|
`runa.tick` accepts a positive integer tick count. Command failures are reported
|
|
in the Runa output channel and an error notification; commands are never retried.
|
|
|
|
## Image source files
|
|
|
|
The image owns actor source text. On connect, **Runa Image Sources** automatically
|
|
shows its virtual filesystem beneath `source` (`runa-image://<endpoint>/source`).
|
|
No workspace changes, folder prompt, or extension restart is required.
|
|
Opening a file reads it from the image; saving writes back to the image.
|
|
The extension never adds image folders to the workspace. VS Code's public API
|
|
does not support overlaying virtual files onto the built-in workspace file tree,
|
|
so image files appear in their own Explorer view backed by the filesystem provider.
|
|
Directories are derived from
|
|
source paths: `actors/counter` appears as `source/actors/counter.rn`. Source
|
|
paths are canonical and exclude the `source/` prefix and `.rn` suffix.
|
|
|
|
- **Save** writes the image's working source with compare-and-swap against the
|
|
last observed `source_id`. If another client changed the file, the save fails
|
|
instead of overwriting; reopen or revert to load the image's text. Saving
|
|
never commits. New `.rn` files are created in the image on first save.
|
|
Deleting and renaming are not supported.
|
|
- **Spawn** uses the latest saved working source, committed or not. If the
|
|
editor has unsaved changes, spawn and commit ask to save first; cancelling
|
|
does nothing. Unsaved editor text is never sent implicitly.
|
|
- **Spawn with State...** opens a JSON input field; cancelling the field does
|
|
not spawn an actor.
|
|
- **Runa: Commit Source** records the saved working source as a new revision
|
|
and reports its revision string.
|
|
- **Runa: Source History** lists revisions for the file and opens the selected
|
|
one as a read-only `runa-source:` document. Revision documents are cached per
|
|
connection session, never change, and remain open after disconnect.
|
|
- **Runa: Roll Back Source** asks for confirmation and replaces the working
|
|
source with the selected revision. It does not change running actors; use
|
|
**Reload** or **Become** to install source into an actor.
|
|
|
|
Server notifications refresh the source tree and clean open editors. For
|
|
automation, `runa.commitSource` accepts a source URI and returns the revision;
|
|
`runa.sourceHistory` accepts a URI and optional revision and returns the opened
|
|
document URI; `runa.rollbackSource` accepts a URI and optional revision and
|
|
returns the new `source_id` after confirmation.
|
|
|
|
## Development and validation
|
|
|
|
From the repository root:
|
|
|
|
```sh
|
|
mise run format
|
|
mise run lint
|
|
mise run test
|
|
mise run test-extension-host
|
|
```
|
|
|
|
The normal test task covers portable-value validation, framing and UTF-8
|
|
fragmentation, subprotocol negotiation, interleaved notifications, refresh
|
|
coalescing, timeout/disconnect behavior, exact 64-bit integer display, and
|
|
interoperation with the real Rust server on an ephemeral loopback port.
|
|
|
|
The separate host test downloads VS Code 1.96.4 to the ignored `.vscode-test/`
|
|
cache in a temporary multi-root workspace and runs source folder save/spawn/
|
|
commit/history/rollback, spawn/send/system-message/tick, connection, inspection,
|
|
disconnect, and reconnect commands
|
|
against a test-owned Rust server. It verifies automatic document updates after
|
|
another client sends messages, pauses, and advances an actor into failure, as
|
|
well as session isolation. On headless Linux:
|
|
|
|
```sh
|
|
xvfb-run -a mise run test-extension-host
|
|
```
|
|
|
|
Compilation diagnostics, detailed runtime event subscriptions, packaging for
|
|
distribution, and debugging remain future work.
|