runa/vscode/README.md

143 lines
7.2 KiB
Markdown

# Runa VS Code client
This is a development client for a trusted localhost Runa image. It uses
the [version 3 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. Expand **Runa Actors** in Explorer. Use its **+** button or **Runa: Spawn Actor**
to choose a published behavior, then enter JSON initial state (for example
`0` for `counter`). There is no default behavior or implicit 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 pause/resume/stop/restart it.
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.
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`.
Behavior publication/installation still requires the REPL or another client.
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 `{ behavior: string, state: string }`, where state is
natural JSON text, and resolves to the new reference. `runa.send` accepts
`{ actor_ref: string }` and JSON message text. `runa.pause`, `runa.resume`,
`runa.stop`, and `runa.restart` accept `{ actor_ref: string }`.
`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.
## Behavior and source browsing
The **Runa Behaviors** view in Explorer lists the image's published behaviors.
Each item shows the current revision; expand it for revision history, newest
first. Tooltips show the implementation identity and the current revision is
marked. Click the behavior to open its current source, or a revision to open
that exact source. **Runa: Open Behavior Source** offers the same choices in
the Command Palette.
Sources are fetched through `get_behavior_source` and opened as read-only
`.rn` virtual documents, not local workspace files. If a Rune language
extension is installed, VS Code can associate its language support with `.rn`.
The source text is preserved exactly, without metadata headers. The URI identifies
the connection session, behavior name, and immutable revision. Documents remain
cached on disconnect and never turn into the latest revision automatically.
Reconnect opens distinct URIs; closing a source document releases its cache.
Cached sources are not persisted across VS Code restarts.
Server notifications refresh both explorers. **Runa: Refresh Image** does the
same on demand. Browsing does not publish code, install actor behavior, tick the
scheduler, or drain runtime events. Source editing and publication remain future
work. For automation, `runa.openBehaviorSource` accepts
`{ name: string, revision: string }` with a positive decimal revision and returns
the opened document URI.
## 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 and runs spawn/send/lifecycle/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
```
Behavior editing and publication,
compilation diagnostics, detailed runtime event subscriptions, packaging for
distribution, and debugging remain future work.