# 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. Open the image's `source` folder (see [Image source files](#image-source-files)). Right-click a `.rn` file and choose **Spawn Actor** (initial state `null`) or **Spawn Actor with State** (enter JSON, 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, the extension mounts it as a writable workspace folder named `source` (`runa-image:///source`). In a saved multi-root workspace this happens automatically; otherwise accept the prompt or run **Runa: Add Image Source Folder** (VS Code may restart extensions when a single-folder window becomes multi-root). 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. - **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.