Skip to content

Web client: aro room server subcommand (hub) #689

Description

@KrisSimon

Context

Child of #687. Server-side counterpart of the room. Reuses the existing SwiftNIO HTTP server, the parser, the LSP wrapper, and the JSONL runtime recorder — all that already exists in this repo.

Surface

```
aro room ./MyApp # bind 127.0.0.1:PORT, print share URL
aro room ./MyApp --listen 0.0.0.0:8090 # explicit
aro room ./MyApp --token READONLY # read-only invite
```

Prints:

```
SOLARO room ready:
http://localhost:8090/?token=ab12cd34
ws://localhost:8090/rooms/main?token=ab12cd34
```

What the hub does

  1. Discover the project — reuse `ApplicationLoader` (`Sources/ARORuntime/Application/ApplicationLoader.swift`).
  2. Serve the web bundle — static files under `/` from the `webclient/dist` directory in the binary's resources (see Web client: aro room server subcommand (hub) #689 / Web client: "Share room" command in SOLARO #692). Falls back to a "build the web client first" page when the bundle isn't shipped.
  3. Accept WebSocket upgrades on `/rooms/{id}` per the protocol in Web client: room wire protocol (WebSocket, JSON-RPC framing) #688.
  4. Watch the directory — reuse `FileMonitor` (`Sources/ARORuntime/FileSystem/FileMonitor.swift`) to detect external edits and broadcast `file-changed`.
  5. Tail the JSONL recorder — the runtime already writes one event per line during a recorded run (`Sources/ARORuntime/Recorder/...`). Stream those frames out as `runtime-event` messages.
  6. Spawn and proxy `aro lsp` — one instance per room (not per client). `lsp` frames bounce through.
  7. Persist last-seen rev per client in `~/.local/share/aro/rooms/{room-id}/state.json` so a reconnect after a disconnect skips the resend.

Things to NOT do in v1

  • No multi-room. One `aro room` invocation = one project = one logical room. Multi-room is a separate process per project.
  • No HTTPS / WSS termination — assume reverse proxy in production. Localhost-only by default for safety.
  • No write throttling. The protocol is naive; a misbehaving client can flood — fine for the trusted-network MVP.

Files

  • `Sources/AROCLI/Commands/RoomCommand.swift` (new)
  • `Sources/ARORuntime/Room/RoomHub.swift` (new — owns the WebSocket fan-out, presence list, file cache)
  • `Sources/ARORuntime/Room/RoomLSPBridge.swift` (new)
  • `Sources/ARORuntime/Room/RoomRuntimeTap.swift` (new — subscribes to the JSONL stream)

Acceptance

  • `aro room ./Examples/SimpleChat` prints a working URL.
  • `websocat` against `ws://…/rooms/main` and a hand-typed `hello` frame returns `welcome` with the file list and an empty `peers` array.
  • `echo "new line" >> Examples/SimpleChat/main.aro` results in a `file-changed` broadcast within 500 ms.
  • Running the project through `aro run` while a client is connected delivers `runtime-event` frames matching the JSONL recorder output.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions