Skip to content

Commit 545fc9b

Browse files
committed
docs(studio-bridge): trim programmatic API and protocol sections from README
1 parent 2f9625b commit 545fc9b

1 file changed

Lines changed: 0 additions & 150 deletions

File tree

tools/studio-bridge/README.md

Lines changed: 0 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -207,156 +207,6 @@ Commands that target a session accept `--target` and `--context`:
207207

208208
When Studio is in Play mode, a single instance has multiple contexts (Edit + Client + Server). The default is `edit`.
209209

210-
## Programmatic API
211-
212-
### Persistent sessions
213-
214-
```typescript
215-
import { BridgeConnection } from '@quenty/studio-bridge';
216-
217-
const connection = await BridgeConnection.connectAsync();
218-
const session = await connection.resolveSessionAsync();
219-
220-
const result = await session.execAsync('return game.PlaceId');
221-
console.log(result.success, result.returnValue);
222-
223-
const state = await session.queryStateAsync();
224-
console.log(state.mode, state.placeName);
225-
226-
const screenshot = await session.captureScreenshotAsync();
227-
// screenshot.base64, screenshot.width, screenshot.height
228-
229-
const logs = await session.queryLogsAsync({ tail: 50 });
230-
// logs.entries: { level, body, timestamp }[]
231-
232-
const tree = await session.queryDataModelAsync({ path: 'Workspace' });
233-
// tree.name, tree.className, tree.children
234-
235-
await connection.disconnectAsync();
236-
```
237-
238-
#### `BridgeConnectionOptions`
239-
240-
| Field | Type | Default | Description |
241-
|-------|------|---------|-------------|
242-
| `port` | `number` | `38741` | Port to bind/connect |
243-
| `timeoutMs` | `number` | `30000` | Connection setup timeout |
244-
| `keepAlive` | `boolean` | `false` | Prevent idle host shutdown |
245-
| `remoteHost` | `string` || Force client mode (`host:port`) |
246-
| `local` | `boolean` | `false` | Skip devcontainer auto-detection |
247-
248-
#### `BridgeSession` methods
249-
250-
| Method | Timeout | Description |
251-
|--------|---------|-------------|
252-
| `execAsync(code, timeout?)` | 120s | Execute Luau code |
253-
| `queryStateAsync()` | 5s | Get Studio mode, place name, IDs |
254-
| `captureScreenshotAsync()` | 15s | Capture viewport PNG |
255-
| `queryLogsAsync(options?)` | 10s | Retrieve buffered log entries |
256-
| `queryDataModelAsync(options)` | 10s | Query instance tree |
257-
| `subscribeAsync(events)` | 5s | Subscribe to push events |
258-
| `unsubscribeAsync(events)` | 5s | Unsubscribe from events |
259-
260-
### One-shot execution (legacy)
261-
262-
```typescript
263-
import { StudioBridge } from '@quenty/studio-bridge';
264-
265-
const bridge = new StudioBridge({ placePath: './build/test.rbxl' });
266-
await bridge.startAsync();
267-
268-
const result = await bridge.executeAsync({
269-
scriptContent: 'print("Hello from studio-bridge!")',
270-
timeoutMs: 90_000,
271-
onOutput: (level, body) => console.log(`[${level}] ${body}`),
272-
});
273-
274-
console.log(result.success); // boolean
275-
console.log(result.logs); // all captured output, newline-separated
276-
277-
await bridge.stopAsync();
278-
```
279-
280-
The legacy API launches Studio, injects a temporary plugin, executes a script, and tears everything down. Use `BridgeConnection` instead for persistent workflows.
281-
282-
## WebSocket Protocol
283-
284-
All messages are JSON: `{ type, sessionId, payload }`. The plugin sends `register` on connect with its capabilities; the server dispatches actions and the plugin replies via `requestId` correlation.
285-
286-
**Plugin to Server:**
287-
288-
| Type | Payload | Description |
289-
|------|---------|-------------|
290-
| `register` | `{ sessionId, capabilities, pluginVersion, … }` | Handshake with capabilities |
291-
| `scriptComplete` | `{ requestId, success, error?, output? }` | Response to `execute` |
292-
| `stateResult` | `{ requestId, mode, placeName, placeId, gameId }` | Response to `queryState` |
293-
| `screenshotResult` | `{ requestId, base64, width, height }` | Response to `captureScreenshot` |
294-
| `dataModelResult` | `{ requestId, instances }` | Response to `queryDataModel` |
295-
| `logsResult` | `{ requestId, entries }` | Response to `queryLogs` |
296-
| `stateChange` | `{ state, previousState }` | Push event on state transition |
297-
| `heartbeat` | `{ uptimeMs, state, pendingRequests }` | Periodic keep-alive |
298-
| `registerActionResult` | `{ requestId, name, success, error? }` | Dynamic action registration result |
299-
| `error` | `{ requestId, code, message }` | Error response |
300-
301-
**Server to Plugin:**
302-
303-
| Type | Payload | Description |
304-
|------|---------|-------------|
305-
| `execute` | `{ requestId, script }` | Luau script to run |
306-
| `queryState` | `{ requestId }` | Request current state |
307-
| `captureScreenshot` | `{ requestId }` | Request viewport screenshot |
308-
| `queryDataModel` | `{ requestId, path, depth?, properties?, attributes? }` | Request instance tree |
309-
| `queryLogs` | `{ requestId, tail?, head?, levels? }` | Request buffered logs |
310-
| `registerAction` | `{ requestId, name, source, responseType? }` | Push a Luau action module dynamically |
311-
| `shutdown` | `{}` | Graceful disconnect |
312-
313-
### Capabilities
314-
315-
Negotiated during handshake: `execute`, `queryState`, `captureScreenshot`, `queryDataModel`, `queryLogs`, `subscribe`, `heartbeat`, `registerAction`.
316-
317-
### Output Levels
318-
319-
`"Print"`, `"Info"`, `"Warning"`, `"Error"` — matches `Enum.MessageType`.
320-
321-
### Error Codes
322-
323-
`UNKNOWN_REQUEST`, `INVALID_PAYLOAD`, `TIMEOUT`, `CAPABILITY_NOT_SUPPORTED`, `INSTANCE_NOT_FOUND`, `PROPERTY_NOT_FOUND`, `SCREENSHOT_FAILED`, `SCRIPT_LOAD_ERROR`, `SCRIPT_RUNTIME_ERROR`, `BUSY`, `SESSION_MISMATCH`, `INTERNAL_ERROR`
324-
325-
## Dynamic Action Registration
326-
327-
The bridge plugin ships as a thin runtime — no static Luau action modules. Instead, action code is pushed dynamically over the wire when a plugin connects:
328-
329-
1. Plugin connects and sends `register` with `registerAction` capability
330-
2. Bridge host scans co-located `.luau` files from `src/commands/<group>/<name>/`
331-
3. Each action's source is sent via `registerAction` message
332-
4. Plugin calls `loadstring()` to install the handler at runtime
333-
334-
This means:
335-
- Adding a new command requires only a `.ts` + `.luau` file in the command directory
336-
- No plugin reinstallation needed when actions change
337-
- Hot-reload during development: reconnect pushes updated action code
338-
339-
## Plugin Discovery
340-
341-
The persistent plugin discovers the bridge host automatically:
342-
343-
1. Poll `GET http://localhost:38741/health` (default port)
344-
2. Health endpoint returns `{ status, port, sessions, uptime }`
345-
3. Connect to `ws://localhost:{port}/plugin`
346-
4. Send `register` message with capabilities
347-
6. Receive `registerAction` messages for each command's Luau action
348-
349-
If the health endpoint is unreachable, the plugin retries with backoff. The plugin survives Studio restarts and reconnects automatically when a host becomes available.
350-
351-
### Role Detection
352-
353-
When a CLI command runs, `BridgeConnection` automatically detects whether to be host or client:
354-
355-
1. If `--remote` specified — connect as client
356-
2. If inside a devcontainer — attempt remote connection first (3s timeout)
357-
3. Try to bind the port — success means become host
358-
4. Port in use — check `/health` — if healthy, become client; if stale, retry
359-
360210
## Testing
361211

362212
```bash

0 commit comments

Comments
 (0)