@el4cteo/rbx-studio-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +203 -0
  3. package/dist/bridge/rpc.js +243 -0
  4. package/dist/bridge/rpc.js.map +1 -0
  5. package/dist/bridge/server.js +281 -0
  6. package/dist/bridge/server.js.map +1 -0
  7. package/dist/index.js +104 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/lib/apidump.js +269 -0
  10. package/dist/lib/apidump.js.map +1 -0
  11. package/dist/lib/errors.js +38 -0
  12. package/dist/lib/errors.js.map +1 -0
  13. package/dist/lib/format.js +191 -0
  14. package/dist/lib/format.js.map +1 -0
  15. package/dist/lib/pluginbuild.js +83 -0
  16. package/dist/lib/pluginbuild.js.map +1 -0
  17. package/dist/lib/png.js +84 -0
  18. package/dist/lib/png.js.map +1 -0
  19. package/dist/lib/protocol.js +22 -0
  20. package/dist/lib/protocol.js.map +1 -0
  21. package/dist/lib/tool.js +27 -0
  22. package/dist/lib/tool.js.map +1 -0
  23. package/dist/resources.js +70 -0
  24. package/dist/resources.js.map +1 -0
  25. package/dist/tools/api.js +78 -0
  26. package/dist/tools/api.js.map +1 -0
  27. package/dist/tools/character.js +94 -0
  28. package/dist/tools/character.js.map +1 -0
  29. package/dist/tools/debug.js +211 -0
  30. package/dist/tools/debug.js.map +1 -0
  31. package/dist/tools/device.js +74 -0
  32. package/dist/tools/device.js.map +1 -0
  33. package/dist/tools/discover.js +217 -0
  34. package/dist/tools/discover.js.map +1 -0
  35. package/dist/tools/exec.js +191 -0
  36. package/dist/tools/exec.js.map +1 -0
  37. package/dist/tools/input.js +96 -0
  38. package/dist/tools/input.js.map +1 -0
  39. package/dist/tools/instances.js +261 -0
  40. package/dist/tools/instances.js.map +1 -0
  41. package/dist/tools/perf.js +367 -0
  42. package/dist/tools/perf.js.map +1 -0
  43. package/dist/tools/playtest.js +153 -0
  44. package/dist/tools/playtest.js.map +1 -0
  45. package/dist/tools/screenshot.js +75 -0
  46. package/dist/tools/screenshot.js.map +1 -0
  47. package/dist/tools/scripts.js +316 -0
  48. package/dist/tools/scripts.js.map +1 -0
  49. package/dist/tools/session.js +152 -0
  50. package/dist/tools/session.js.map +1 -0
  51. package/dist/tools/world.js +281 -0
  52. package/dist/tools/world.js.map +1 -0
  53. package/package.json +62 -0
  54. package/plugin/default.project.json +6 -0
  55. package/plugin/src/Config.luau +59 -0
  56. package/plugin/src/Console.luau +657 -0
  57. package/plugin/src/Context.luau +35 -0
  58. package/plugin/src/Dispatch.luau +90 -0
  59. package/plugin/src/Editor.luau +142 -0
  60. package/plugin/src/Emulation.luau +151 -0
  61. package/plugin/src/LogBuffer.luau +277 -0
  62. package/plugin/src/Net.luau +102 -0
  63. package/plugin/src/Paths.luau +255 -0
  64. package/plugin/src/Phrase.luau +465 -0
  65. package/plugin/src/Png.luau +238 -0
  66. package/plugin/src/Scope.luau +78 -0
  67. package/plugin/src/ScriptEdit.luau +100 -0
  68. package/plugin/src/Serialize.luau +287 -0
  69. package/plugin/src/TextEdit.luau +296 -0
  70. package/plugin/src/Transport.luau +328 -0
  71. package/plugin/src/Undo.luau +72 -0
  72. package/plugin/src/Visuals.luau +710 -0
  73. package/plugin/src/handlers/Api.luau +242 -0
  74. package/plugin/src/handlers/Assets.luau +145 -0
  75. package/plugin/src/handlers/Capture.luau +187 -0
  76. package/plugin/src/handlers/Character.luau +361 -0
  77. package/plugin/src/handlers/Debug.luau +391 -0
  78. package/plugin/src/handlers/Device.luau +119 -0
  79. package/plugin/src/handlers/Discover.luau +289 -0
  80. package/plugin/src/handlers/Exec.luau +270 -0
  81. package/plugin/src/handlers/Geometry.luau +261 -0
  82. package/plugin/src/handlers/Input.luau +287 -0
  83. package/plugin/src/handlers/Instances.luau +389 -0
  84. package/plugin/src/handlers/Perf.luau +645 -0
  85. package/plugin/src/handlers/Playtest.luau +205 -0
  86. package/plugin/src/handlers/Scripts.luau +387 -0
  87. package/plugin/src/handlers/Session.luau +168 -0
  88. package/plugin/src/handlers/Viewport.luau +302 -0
  89. package/plugin/src/handlers/World.luau +176 -0
  90. package/plugin/src/init.server.luau +317 -0
  91. package/scripts/build-plugin.mjs +157 -0
  92. package/scripts/check-plugin.mjs +97 -0
  93. package/scripts/install-plugin.mjs +39 -0
  94. package/scripts/latency.mjs +201 -0
  95. package/scripts/locate-luau.mjs +51 -0
  96. package/scripts/sourcemap.mjs +58 -0
  97. package/scripts/test-plugin.mjs +82 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,203 @@
1
+ # Roblox Studio MCP
2
+
3
+ MCP server for Roblox Studio. 29 tools over a push-based bridge. MIT.
4
+
5
+ ## Install
6
+
7
+ **1. The Studio plugin**
8
+
9
+ ```bash
10
+ npx -y @el4cteo/rbx-studio-mcp --install-plugin
11
+ ```
12
+
13
+ Or download `StudioMCP.rbxmx` from [Releases](https://github.com/EL4CTEO/roblox-studio-mcp/releases) into your Studio plugins folder.
14
+
15
+ **2. The server**, in whichever client you use:
16
+
17
+ <details>
18
+ <summary><b>Claude Code</b></summary>
19
+
20
+ ```bash
21
+ claude mcp add roblox-studio -- npx -y @el4cteo/rbx-studio-mcp
22
+ ```
23
+ </details>
24
+
25
+ <details>
26
+ <summary><b>Codex CLI</b></summary>
27
+
28
+ ```bash
29
+ codex mcp add roblox-studio -- npx -y @el4cteo/rbx-studio-mcp
30
+ ```
31
+
32
+ Or in `~/.codex/config.toml`:
33
+
34
+ ```toml
35
+ [mcp_servers.roblox-studio]
36
+ command = "npx"
37
+ args = ["-y", "@el4cteo/rbx-studio-mcp"]
38
+ ```
39
+ </details>
40
+
41
+ <details>
42
+ <summary><b>Cursor</b></summary>
43
+
44
+ `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per project):
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "roblox-studio": {
50
+ "command": "npx",
51
+ "args": ["-y", "@el4cteo/rbx-studio-mcp"]
52
+ }
53
+ }
54
+ }
55
+ ```
56
+ </details>
57
+
58
+ <details>
59
+ <summary><b>opencode</b></summary>
60
+
61
+ `opencode.json`:
62
+
63
+ ```json
64
+ {
65
+ "$schema": "https://opencode.ai/config.json",
66
+ "mcp": {
67
+ "roblox-studio": {
68
+ "type": "local",
69
+ "command": ["npx", "-y", "@el4cteo/rbx-studio-mcp"],
70
+ "enabled": true
71
+ }
72
+ }
73
+ }
74
+ ```
75
+ </details>
76
+
77
+ <details>
78
+ <summary><b>Claude Desktop</b></summary>
79
+
80
+ `claude_desktop_config.json`:
81
+
82
+ ```json
83
+ {
84
+ "mcpServers": {
85
+ "roblox-studio": {
86
+ "command": "npx",
87
+ "args": ["-y", "@el4cteo/rbx-studio-mcp"]
88
+ }
89
+ }
90
+ }
91
+ ```
92
+ </details>
93
+
94
+ <details>
95
+ <summary><b>VS Code / Copilot</b></summary>
96
+
97
+ `.vscode/mcp.json`:
98
+
99
+ ```json
100
+ {
101
+ "servers": {
102
+ "roblox-studio": {
103
+ "type": "stdio",
104
+ "command": "npx",
105
+ "args": ["-y", "@el4cteo/rbx-studio-mcp"]
106
+ }
107
+ }
108
+ }
109
+ ```
110
+ </details>
111
+
112
+ <details>
113
+ <summary><b>Gemini CLI</b></summary>
114
+
115
+ `~/.gemini/settings.json`:
116
+
117
+ ```json
118
+ {
119
+ "mcpServers": {
120
+ "roblox-studio": {
121
+ "command": "npx",
122
+ "args": ["-y", "@el4cteo/rbx-studio-mcp"]
123
+ }
124
+ }
125
+ }
126
+ ```
127
+ </details>
128
+
129
+ <details>
130
+ <summary><b>Windsurf</b></summary>
131
+
132
+ `~/.codeium/windsurf/mcp_config.json`:
133
+
134
+ ```json
135
+ {
136
+ "mcpServers": {
137
+ "roblox-studio": {
138
+ "command": "npx",
139
+ "args": ["-y", "@el4cteo/rbx-studio-mcp"]
140
+ }
141
+ }
142
+ }
143
+ ```
144
+ </details>
145
+
146
+ **3.** Open Studio, accept the `127.0.0.1` prompt, check the **Studio MCP** toolbar button. Verify with `studio_status`.
147
+
148
+ Port defaults to **44755** — `--port` or `ROBLOX_STUDIO_MCP_PORT`, matched in the plugin widget. Loopback only.
149
+
150
+ ## Tools
151
+
152
+ | | |
153
+ |---|---|
154
+ | **Discover** | `studio_status` `tree` `inspect` `find` `api` |
155
+ | **Scripts** | `script_read` `script_edit` `script_grep` `script_create` |
156
+ | **Instances** | `create` `modify` `delete` `move` |
157
+ | **World** | `geometry` `assets` `collision` `undo` |
158
+ | **Run & debug** | `playtest` `execute_luau` `character` `input` `console` `debug` `performance` |
159
+ | **Look** | `screenshot` `viewport` `device` |
160
+ | **Session** | `list_studios` `set_active_studio` |
161
+
162
+ Gotchas: `screenshot` doesn't work mid-playtest. `debug` needs **API debugger Luau** in `File → Beta Features`. `device` emulation persists until `device op="stop"`.
163
+
164
+ ## Compared to what else exists
165
+
166
+ | | tools | transport | editor-safe writes | undo recording | live API dump | licence |
167
+ |---|---|---|---|---|---|---|
168
+ | **this** | 29 | **SSE push** | **yes** | **yes** | **yes** | MIT |
169
+ | [Roblox built-in](https://create.roblox.com/docs/studio/mcp) | ~27 | stdio | partial | — | n/a | closed source |
170
+ | [Chrrxs](https://github.com/Chrrxs/robloxstudio-mcp) | ~40 | poll | no | partial | no | MIT |
171
+ | [drgost1](https://github.com/drgost1/robloxstudio-mcp) | 51 | poll 500 ms | no | yes | no | MIT |
172
+ | [boshyxd](https://github.com/boshyxd/robloxstudio-mcp) | 43 | long-poll | no | no | no | MIT (archived) |
173
+ | [Roblox/studio-rust-mcp-server](https://github.com/Roblox/studio-rust-mcp-server) | 2 | HTTP | no | no | no | MIT (superseded) |
174
+
175
+ - **Push, not poll.** SSE stream instead of a 500 ms poll. 50 sequential round trips: **13.6 ms** mean vs 25.8 ms, **12.8 ms** median vs 29.9 ms. Reproduce with `node scripts/latency.mjs --count 50 --compare`.
176
+ - **Safe script edits.** `ScriptEditorService:UpdateSourceAsync`, not `script.Source` — your unsaved editor buffer survives. Batches are all-or-nothing.
177
+ - **One Ctrl+Z per action**, via `ChangeHistoryService`.
178
+ - **29 tools, ~16k tokens of schema**, against 43–51 elsewhere. Cursor-paged, capped, with `detail: concise | standard | full`.
179
+ - **Live API dump** for property validation, so typos get suggestions (`Anchorred` → `Anchored`).
180
+
181
+ Not built here: terrain, AI mesh and material generation.
182
+
183
+ ## Security
184
+
185
+ Binds `127.0.0.1`, rejects requests carrying `Origin`, and requires a header a browser cannot set cross-origin — closing the DNS-rebinding hole. Studio grants HTTP per plugin and per URL, so your experience's "Allow HTTP Requests" setting is untouched.
186
+
187
+ ## Development
188
+
189
+ ```bash
190
+ npm install
191
+ npm run build # TypeScript -> dist/
192
+ npm run build:plugin # plugin/src -> build/StudioMCP.rbxmx
193
+ npm run install:plugin # build + copy into the Studio plugins folder
194
+ npm test # Luau unit tests
195
+ ```
196
+
197
+ Needs `luau`, `luau-compile` and `luau-analyze` from [the Luau releases](https://github.com/luau-lang/luau/releases) on `PATH` or in `tools/`.
198
+
199
+ `evals/` holds ten questions answerable only by driving a real Studio session — see [evals/README.md](evals/README.md).
200
+
201
+ ## Licence
202
+
203
+ MIT.
@@ -0,0 +1,243 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { AMBIGUOUS_STUDIO, DISCONNECTED, NO_STUDIO, TIMEOUT, ToolError, } from "../lib/errors.js";
3
+ /** Default per-command deadline. Studio round trips are single-digit ms over SSE. */
4
+ export const DEFAULT_TIMEOUT_MS = 15_000;
5
+ /** How long a long-poll request is parked before we answer "idle". */
6
+ export const POLL_HOLD_MS = 25_000;
7
+ /** A session is considered dead if we have not heard from it in this long. */
8
+ const STALE_AFTER_MS = 90_000;
9
+ /**
10
+ * Owns every connected Studio and the in-flight request table.
11
+ *
12
+ * The two transports converge here: `deliver` either writes straight to an open
13
+ * SSE stream or parks the command for the next long-poll. Tools call `call()`
14
+ * and never learn which one was used.
15
+ */
16
+ export class Bridge {
17
+ sessions = new Map();
18
+ activeStudioId = null;
19
+ /**
20
+ * Whether `activeStudioId` was picked by the user via set_active_studio, as
21
+ * opposed to being the only session that happened to connect first.
22
+ *
23
+ * The distinction decides what happens when a second Studio appears. A
24
+ * defaulted target silently becomes ambiguous — editing whichever place
25
+ * connected first is not a reasonable guess — while a chosen one stays put,
26
+ * because the user said which place they meant.
27
+ */
28
+ activeWasChosen = false;
29
+ // --- session lifecycle -------------------------------------------------
30
+ attach(identity, stream) {
31
+ const existing = this.sessions.get(identity.studioId);
32
+ if (existing) {
33
+ // Studio reconnected (SSE hit the 30-minute cap, or the plugin reloaded).
34
+ // Keep pending calls alive across the gap so an in-flight tool survives.
35
+ existing.stream?.end();
36
+ existing.identity = identity;
37
+ existing.stream = stream;
38
+ existing.lastSeenAt = Date.now();
39
+ this.flush(existing);
40
+ return identity.studioId;
41
+ }
42
+ this.sessions.set(identity.studioId, {
43
+ identity,
44
+ connectedAt: Date.now(),
45
+ lastSeenAt: Date.now(),
46
+ stream,
47
+ queue: [],
48
+ waiter: null,
49
+ pending: new Map(),
50
+ });
51
+ this.activeStudioId ??= identity.studioId;
52
+ return identity.studioId;
53
+ }
54
+ detach(studioId) {
55
+ const session = this.sessions.get(studioId);
56
+ if (!session)
57
+ return;
58
+ for (const pending of session.pending.values()) {
59
+ clearTimeout(pending.timer);
60
+ pending.reject(DISCONNECTED());
61
+ }
62
+ session.pending.clear();
63
+ session.waiter?.(null);
64
+ session.stream?.end();
65
+ this.sessions.delete(studioId);
66
+ if (this.activeStudioId === studioId) {
67
+ // The place the user chose is gone, so the replacement is a fallback, not
68
+ // a choice: mark it as such so a remaining pair goes ambiguous again.
69
+ this.activeStudioId = this.sessions.keys().next().value ?? null;
70
+ this.activeWasChosen = false;
71
+ }
72
+ }
73
+ /** Drops sessions whose plugin stopped checking in without a clean detach. */
74
+ reapStale() {
75
+ const cutoff = Date.now() - STALE_AFTER_MS;
76
+ for (const [id, session] of this.sessions) {
77
+ if (session.lastSeenAt < cutoff && !session.stream)
78
+ this.detach(id);
79
+ }
80
+ }
81
+ touch(studioId) {
82
+ const session = this.sessions.get(studioId);
83
+ if (session)
84
+ session.lastSeenAt = Date.now();
85
+ }
86
+ /**
87
+ * Records the place name a status call resolved.
88
+ *
89
+ * The identity announced at connect can only carry the data model's name
90
+ * ("Place1"), because the real one takes a web lookup. Once any call has paid
91
+ * for that lookup, every later mention of the session should use the name the
92
+ * user recognises rather than reverting to the one they do not.
93
+ */
94
+ notePlaceName(studioId, placeName, context) {
95
+ const session = this.sessions.get(studioId);
96
+ if (!session)
97
+ return;
98
+ if (placeName)
99
+ session.identity.placeName = placeName;
100
+ if (context)
101
+ session.identity.context = context;
102
+ }
103
+ has(studioId) {
104
+ return this.sessions.has(studioId);
105
+ }
106
+ list() {
107
+ return [...this.sessions.values()].map((session) => ({
108
+ ...session.identity,
109
+ connectedAt: session.connectedAt,
110
+ lastSeenAt: session.lastSeenAt,
111
+ }));
112
+ }
113
+ get activeId() {
114
+ return this.activeStudioId;
115
+ }
116
+ /** True only once the user has actually picked a target. */
117
+ get activeIsChosen() {
118
+ return this.activeWasChosen;
119
+ }
120
+ setActive(studioId) {
121
+ if (!this.sessions.has(studioId)) {
122
+ throw new ToolError("UNKNOWN_STUDIO", `No connected Studio has id "${studioId}".`, "Call list_studios to see the connected instances and their ids.");
123
+ }
124
+ this.activeStudioId = studioId;
125
+ this.activeWasChosen = true;
126
+ }
127
+ // --- request/response --------------------------------------------------
128
+ /**
129
+ * Sends `op` to a Studio instance and resolves with its `data` payload.
130
+ * Rejects with a ToolError carrying an agent-readable hint on any failure,
131
+ * including errors raised inside the plugin.
132
+ */
133
+ call(op, params = {}, options = {}) {
134
+ const session = this.resolveSession(options.studioId);
135
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
136
+ const command = { id: randomUUID(), op, params };
137
+ return new Promise((resolve, reject) => {
138
+ const timer = setTimeout(() => {
139
+ session.pending.delete(command.id);
140
+ reject(TIMEOUT(op, timeoutMs));
141
+ }, timeoutMs);
142
+ session.pending.set(command.id, {
143
+ resolve: resolve,
144
+ reject,
145
+ timer,
146
+ op,
147
+ });
148
+ this.deliver(session, command);
149
+ });
150
+ }
151
+ /** Settles the promise a plugin result belongs to. Unknown ids are ignored. */
152
+ settle(studioId, result) {
153
+ const session = this.sessions.get(studioId);
154
+ if (!session)
155
+ return;
156
+ session.lastSeenAt = Date.now();
157
+ const pending = session.pending.get(result.id);
158
+ if (!pending)
159
+ return; // already timed out; the tool has moved on
160
+ session.pending.delete(result.id);
161
+ clearTimeout(pending.timer);
162
+ if (result.ok) {
163
+ pending.resolve(result.data);
164
+ }
165
+ else {
166
+ pending.reject(result.error
167
+ ? ToolError.fromCommandError(result.error)
168
+ : new ToolError("PLUGIN_ERROR", `Studio failed to run "${pending.op}".`));
169
+ }
170
+ }
171
+ /**
172
+ * Parks a long-poll request until a command arrives or the hold expires.
173
+ * Resolves null on expiry so the plugin can re-poll with a fresh request
174
+ * rather than sitting on a connection Studio may time out underneath it.
175
+ */
176
+ waitForCommand(studioId) {
177
+ const session = this.sessions.get(studioId);
178
+ if (!session)
179
+ return Promise.resolve(null);
180
+ session.lastSeenAt = Date.now();
181
+ const queued = session.queue.shift();
182
+ if (queued)
183
+ return Promise.resolve(queued);
184
+ return new Promise((resolve) => {
185
+ const settle = (command) => {
186
+ clearTimeout(timer);
187
+ session.waiter = null;
188
+ resolve(command);
189
+ };
190
+ const timer = setTimeout(() => {
191
+ if (session.waiter === settle)
192
+ session.waiter = null;
193
+ resolve(null);
194
+ }, POLL_HOLD_MS);
195
+ session.waiter = settle;
196
+ });
197
+ }
198
+ // --- internals ---------------------------------------------------------
199
+ resolveSession(studioId) {
200
+ if (studioId) {
201
+ const session = this.sessions.get(studioId);
202
+ if (!session)
203
+ throw NO_STUDIO();
204
+ return session;
205
+ }
206
+ if (this.sessions.size === 0)
207
+ throw NO_STUDIO();
208
+ // One Studio is never ambiguous, whether or not anyone chose it.
209
+ const only = this.sessions.values().next().value;
210
+ if (this.sessions.size === 1 && only)
211
+ return only;
212
+ if (this.activeWasChosen && this.activeStudioId) {
213
+ const session = this.sessions.get(this.activeStudioId);
214
+ if (session)
215
+ return session;
216
+ }
217
+ throw AMBIGUOUS_STUDIO(
218
+ // The context is the part that decides it. Two rows reading "Untitled
219
+ // Experience" are indistinguishable, and picking the playtest means work
220
+ // that disappears when it stops.
221
+ this.list().map((session) => `${session.studioId} (${session.placeName}${session.context ? `, ${session.context}` : ""})`));
222
+ }
223
+ deliver(session, command) {
224
+ if (session.stream && !session.stream.writableEnded) {
225
+ session.stream.write(`data: ${JSON.stringify(command)}\n\n`);
226
+ return;
227
+ }
228
+ if (session.waiter) {
229
+ session.waiter(command);
230
+ return;
231
+ }
232
+ session.queue.push(command);
233
+ }
234
+ /** Hands any queued commands to a stream that just (re)connected. */
235
+ flush(session) {
236
+ if (!session.stream || session.stream.writableEnded)
237
+ return;
238
+ for (const command of session.queue.splice(0)) {
239
+ session.stream.write(`data: ${JSON.stringify(command)}\n\n`);
240
+ }
241
+ }
242
+ }
243
+ //# sourceMappingURL=rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/bridge/rpc.ts"],"names":[],"mappings":"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"}