@chrrxs/robloxstudio-mcp 2.15.1 → 2.16.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.
- package/dist/index.js +1292 -281
- package/package.json +1 -1
- package/studio-plugin/MCPInspectorPlugin.rbxmx +494 -203
- package/studio-plugin/MCPPlugin.rbxmx +494 -203
- package/studio-plugin/src/modules/ClientBroker.ts +7 -2
- package/studio-plugin/src/modules/Communication.ts +6 -12
- package/studio-plugin/src/modules/EvalBridges.ts +96 -68
- package/studio-plugin/src/modules/LuauExec.ts +134 -36
- package/studio-plugin/src/modules/RuntimeLogBuffer.ts +9 -9
- package/studio-plugin/src/modules/handlers/EvalRuntimeHandlers.ts +149 -0
- package/studio-plugin/src/modules/handlers/LogHandlers.ts +5 -6
- package/studio-plugin/src/modules/handlers/TestHandlers.ts +2 -33
- package/studio-plugin/src/server/index.server.ts +27 -8
|
@@ -10,6 +10,9 @@ local State = TS.import(script, script, "modules", "State")
|
|
|
10
10
|
local UI = TS.import(script, script, "modules", "UI")
|
|
11
11
|
local Communication = TS.import(script, script, "modules", "Communication")
|
|
12
12
|
local ClientBroker = TS.import(script, script, "modules", "ClientBroker")
|
|
13
|
+
local _EvalBridges = TS.import(script, script, "modules", "EvalBridges")
|
|
14
|
+
local cleanupLegacyEditBridges = _EvalBridges.cleanupLegacyEditBridges
|
|
15
|
+
local ensureRuntimeBridgeInstalled = _EvalBridges.ensureRuntimeBridgeInstalled
|
|
13
16
|
local RuntimeLogBuffer = TS.import(script, script, "modules", "RuntimeLogBuffer")
|
|
14
17
|
local StopPlayMonitor = TS.import(script, script, "modules", "StopPlayMonitor")
|
|
15
18
|
local RenderMonitor = TS.import(script, script, "modules", "RenderMonitor")
|
|
@@ -30,13 +33,24 @@ local elements = UI.getElements()
|
|
|
30
33
|
local ICON_DISCONNECTED = "rbxassetid://75876056391496"
|
|
31
34
|
local ICON_CONNECTING = "rbxassetid://71302583919560"
|
|
32
35
|
local ICON_CONNECTED = "rbxassetid://130958234173611"
|
|
33
|
-
local
|
|
34
|
-
local
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
local TOOLBAR_REGISTRATION_DELAY_SECONDS = 1
|
|
37
|
+
local toolbarButtonRegistered = false
|
|
38
|
+
local function registerToolbarButton()
|
|
39
|
+
if toolbarButtonRegistered then
|
|
40
|
+
return nil
|
|
41
|
+
end
|
|
42
|
+
toolbarButtonRegistered = true
|
|
43
|
+
local toolbar = plugin:CreateToolbar("MCP Integration")
|
|
44
|
+
local button = toolbar:CreateButton("MCP Server", "Connect to MCP Server for AI Integration", ICON_DISCONNECTED)
|
|
45
|
+
UI.setToolbarButton(button, {
|
|
46
|
+
disconnected = ICON_DISCONNECTED,
|
|
47
|
+
connecting = ICON_CONNECTING,
|
|
48
|
+
connected = ICON_CONNECTED,
|
|
49
|
+
})
|
|
50
|
+
button.Click:Connect(function()
|
|
51
|
+
elements.screenGui.Enabled = not elements.screenGui.Enabled
|
|
52
|
+
end)
|
|
53
|
+
end
|
|
40
54
|
elements.connectButton.Activated:Connect(function()
|
|
41
55
|
local conn = State.getActiveConnection()
|
|
42
56
|
if conn and conn.isActive then
|
|
@@ -45,20 +59,26 @@ elements.connectButton.Activated:Connect(function()
|
|
|
45
59
|
Communication.activatePlugin(State.getActiveTabIndex())
|
|
46
60
|
end
|
|
47
61
|
end)
|
|
48
|
-
button.Click:Connect(function()
|
|
49
|
-
elements.screenGui.Enabled = not elements.screenGui.Enabled
|
|
50
|
-
end)
|
|
51
62
|
plugin.Unloading:Connect(function()
|
|
52
63
|
Communication.deactivateAll()
|
|
53
64
|
end)
|
|
54
65
|
UI.updateUIState()
|
|
55
66
|
Communication.checkForUpdates()
|
|
67
|
+
task.delay(TOOLBAR_REGISTRATION_DELAY_SECONDS, registerToolbarButton)
|
|
56
68
|
-- Auto-activate per peer. The boshyxd plugin only registers with MCP when the
|
|
57
69
|
-- user clicks Connect in its UI, but that UI is invisible in play DMs - so
|
|
58
70
|
-- play peers' plugin instances load without ever registering. Run after a
|
|
59
71
|
-- short delay so the UI/State have a chance to initialize first.
|
|
60
72
|
task.delay(2, function()
|
|
61
73
|
local role = ClientBroker.forkRole()
|
|
74
|
+
if role == "edit" then
|
|
75
|
+
cleanupLegacyEditBridges()
|
|
76
|
+
else
|
|
77
|
+
local result = ensureRuntimeBridgeInstalled()
|
|
78
|
+
if not result.installed then
|
|
79
|
+
warn(`[MCPPlugin] Runtime eval bridge install failed: {result.error}`)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
62
82
|
if role == "edit" or role == "server" then
|
|
63
83
|
pcall(function()
|
|
64
84
|
local idx = State.getActiveTabIndex()
|
|
@@ -105,6 +125,7 @@ local MemoryHandlers = TS.import(script, script.Parent, "handlers", "MemoryHandl
|
|
|
105
125
|
local SceneAnalysisHandlers = TS.import(script, script.Parent, "handlers", "SceneAnalysisHandlers")
|
|
106
126
|
local CaptureHandlers = TS.import(script, script.Parent, "handlers", "CaptureHandlers")
|
|
107
127
|
local InputHandlers = TS.import(script, script.Parent, "handlers", "InputHandlers")
|
|
128
|
+
local EvalRuntimeHandlers = TS.import(script, script.Parent, "handlers", "EvalRuntimeHandlers")
|
|
108
129
|
local LuauExec = TS.import(script, script.Parent, "LuauExec")
|
|
109
130
|
local State = TS.import(script, script.Parent, "State")
|
|
110
131
|
local StudioTestService = game:GetService("StudioTestService")
|
|
@@ -167,6 +188,7 @@ local BROKER_OWNER_ATTRIBUTE = "__MCPBrokerOwner"
|
|
|
167
188
|
-- cache / etc. lives there) so the server peer alone can't satisfy them.
|
|
168
189
|
local CLIENT_BROKER_ALLOWED_ENDPOINTS = {
|
|
169
190
|
["/api/execute-luau"] = true,
|
|
191
|
+
["/api/eval-runtime"] = true,
|
|
170
192
|
["/api/get-runtime-logs"] = true,
|
|
171
193
|
["/api/get-memory-breakdown"] = true,
|
|
172
194
|
["/api/get-scene-analysis"] = true,
|
|
@@ -247,8 +269,8 @@ local function handleGetRuntimeLogs(data)
|
|
|
247
269
|
local since = d.since
|
|
248
270
|
local tail = d.tail
|
|
249
271
|
local filter = d.filter
|
|
250
|
-
-- "client" is the generic
|
|
251
|
-
-- the specific role (e.g. "client-1")
|
|
272
|
+
-- "client" is the generic capture tag; MCP-side aggregation overrides it
|
|
273
|
+
-- with the specific role (e.g. "client-1") for capturedBy.
|
|
252
274
|
return RuntimeLogBuffer.query({
|
|
253
275
|
since = since,
|
|
254
276
|
tail = tail,
|
|
@@ -366,6 +388,9 @@ local function setupClientBroker()
|
|
|
366
388
|
if payload and payload.endpoint == "/api/execute-luau" then
|
|
367
389
|
return handleExecuteLuau(payload.data)
|
|
368
390
|
end
|
|
391
|
+
if payload and payload.endpoint == "/api/eval-runtime" then
|
|
392
|
+
return EvalRuntimeHandlers.evalRuntime(payload.data or {})
|
|
393
|
+
end
|
|
369
394
|
-- Legacy: raw execute-luau payload at the top level.
|
|
370
395
|
return handleExecuteLuau(payload)
|
|
371
396
|
end
|
|
@@ -547,7 +572,7 @@ local ServerStorage = _services.ServerStorage
|
|
|
547
572
|
local State = TS.import(script, script.Parent, "State")
|
|
548
573
|
local Utils = TS.import(script, script.Parent, "Utils")
|
|
549
574
|
local UI = TS.import(script, script.Parent, "UI")
|
|
550
|
-
local
|
|
575
|
+
local cleanupLegacyEditBridges = TS.import(script, script.Parent, "EvalBridges").cleanupLegacyEditBridges
|
|
551
576
|
local QueryHandlers = TS.import(script, script.Parent, "handlers", "QueryHandlers")
|
|
552
577
|
local PropertyHandlers = TS.import(script, script.Parent, "handlers", "PropertyHandlers")
|
|
553
578
|
local InstanceHandlers = TS.import(script, script.Parent, "handlers", "InstanceHandlers")
|
|
@@ -562,6 +587,7 @@ local LogHandlers = TS.import(script, script.Parent, "handlers", "LogHandlers")
|
|
|
562
587
|
local SerializationHandlers = TS.import(script, script.Parent, "handlers", "SerializationHandlers")
|
|
563
588
|
local MemoryHandlers = TS.import(script, script.Parent, "handlers", "MemoryHandlers")
|
|
564
589
|
local SceneAnalysisHandlers = TS.import(script, script.Parent, "handlers", "SceneAnalysisHandlers")
|
|
590
|
+
local EvalRuntimeHandlers = TS.import(script, script.Parent, "handlers", "EvalRuntimeHandlers")
|
|
565
591
|
-- Per-plugin-load random GUID. Used as the /poll URL param so the server
|
|
566
592
|
-- can tell our polls apart from any other plugin's polls. Not user-facing —
|
|
567
593
|
-- MCP tools and the LLM operate on instanceId (the place identifier).
|
|
@@ -668,6 +694,7 @@ local routeMap = {
|
|
|
668
694
|
["/api/get-tagged"] = MetadataHandlers.getTagged,
|
|
669
695
|
["/api/get-selection"] = MetadataHandlers.getSelection,
|
|
670
696
|
["/api/execute-luau"] = MetadataHandlers.executeLuau,
|
|
697
|
+
["/api/eval-runtime"] = EvalRuntimeHandlers.evalRuntime,
|
|
671
698
|
["/api/undo"] = MetadataHandlers.undo,
|
|
672
699
|
["/api/redo"] = MetadataHandlers.redo,
|
|
673
700
|
["/api/bulk-set-attributes"] = MetadataHandlers.bulkSetAttributes,
|
|
@@ -1049,18 +1076,10 @@ local function activatePlugin(connIndex)
|
|
|
1049
1076
|
-- Initial /ready; pollForRequests will also re-fire ready if the server
|
|
1050
1077
|
-- later reports knownInstance=false (process restart, etc).
|
|
1051
1078
|
sendReady(conn)
|
|
1052
|
-
--
|
|
1053
|
-
--
|
|
1054
|
-
-- clones them into the play DMs and eval_*_runtime works with no setup
|
|
1055
|
-
-- roundtrip. Only the edit DM installs; play DMs already have the cloned
|
|
1056
|
-
-- copies. Idempotent, so reconnects don't re-dirty the place.
|
|
1079
|
+
-- Remove legacy edit-mode eval bridge scripts from older plugin builds.
|
|
1080
|
+
-- Current bridges are created only in running play DataModels.
|
|
1057
1081
|
if not RunService:IsRunning() then
|
|
1058
|
-
task.spawn(
|
|
1059
|
-
local result = ensureBridgesInstalled()
|
|
1060
|
-
if not result.installed then
|
|
1061
|
-
warn(`[MCPPlugin] Eval bridge install failed: {result.error}`)
|
|
1062
|
-
end
|
|
1063
|
-
end)
|
|
1082
|
+
task.spawn(cleanupLegacyEditBridges)
|
|
1064
1083
|
end
|
|
1065
1084
|
-- Watch for game.Name updates so a stale "Place1" captured at first
|
|
1066
1085
|
-- /ready gets refreshed once Studio settles on the real DM name.
|
|
@@ -1181,29 +1200,15 @@ local TS = require(script.Parent.Parent.include.RuntimeLib)
|
|
|
1181
1200
|
-- ServerScriptService.LoadStringEnabled, so eval_server_runtime works even
|
|
1182
1201
|
-- when LoadStringEnabled=false (the default in fresh places).
|
|
1183
1202
|
--
|
|
1184
|
-
-- Lifecycle:
|
|
1185
|
-
--
|
|
1186
|
-
--
|
|
1187
|
-
--
|
|
1188
|
-
--
|
|
1189
|
-
-- DM after a playtest ends (rather than cleaning up) so that a playtest the
|
|
1190
|
-
-- dev starts MANUALLY via the Studio Play button — not the MCP start_playtest
|
|
1191
|
-
-- tool — also gets the bridges cloned in. This is intentionally a little
|
|
1192
|
-
-- intrusive (two helper scripts visible in Explorer) in exchange for a
|
|
1193
|
-
-- zero-roundtrip eval_*_runtime experience for devs working 1:1 with an agent.
|
|
1194
|
-
--
|
|
1195
|
-
-- Archivable handling: ExecutePlayModeAsync's deep-clone SKIPS instances
|
|
1196
|
-
-- with Archivable=false (verified empirically in v2.9.0 testing - bridges
|
|
1197
|
-
-- never reached the play DMs because we'd set them to false). We now keep
|
|
1198
|
-
-- Archivable=true so the clone works, and rely on cleanupBridges() to
|
|
1199
|
-
-- remove the scripts from the edit DM when the test ends. The only failure
|
|
1200
|
-
-- mode is the user saving DURING an active playtest, which would persist
|
|
1201
|
-
-- the bridges to the .rbxl - that's a no-op next session because
|
|
1202
|
-
-- installBridges() always calls cleanupBridges() first to clear stale
|
|
1203
|
-
-- instances. The RemoteFunction/BindableFunction that the bridge scripts
|
|
1204
|
-
-- CREATE at runtime stay Archivable=false (they're runtime-only and should
|
|
1205
|
-
-- never appear in a save).
|
|
1203
|
+
-- Lifecycle: bridge scripts are created only in running play DataModels.
|
|
1204
|
+
-- The server plugin peer creates the Script in runtime ServerScriptService;
|
|
1205
|
+
-- each client plugin peer creates its LocalScript in that client's
|
|
1206
|
+
-- PlayerScripts. Nothing is installed into the edit DataModel anymore.
|
|
1207
|
+
-- Runtime-created scripts disappear naturally when the playtest stops.
|
|
1206
1208
|
local _services = TS.import(script, script.Parent.Parent, "node_modules", "@rbxts", "services")
|
|
1209
|
+
local Players = _services.Players
|
|
1210
|
+
local ReplicatedStorage = _services.ReplicatedStorage
|
|
1211
|
+
local RunService = _services.RunService
|
|
1207
1212
|
local ServerScriptService = _services.ServerScriptService
|
|
1208
1213
|
local StarterPlayer = _services.StarterPlayer
|
|
1209
1214
|
local ScriptEditorService = game:GetService("ScriptEditorService")
|
|
@@ -1242,9 +1247,10 @@ bf.Archivable = false\
|
|
|
1242
1247
|
bf.Parent = ServerScriptService\
|
|
1243
1248
|
bf.OnInvoke = function(payload)\
|
|
1244
1249
|
if typeof(payload) ~= "Instance" or not payload:IsA("ModuleScript") then\
|
|
1245
|
-
return false, "payload must be a ModuleScript instance"\
|
|
1250
|
+
return \{ ok = false, value = "payload must be a ModuleScript instance" \}\
|
|
1246
1251
|
end\
|
|
1247
|
-
|
|
1252
|
+
local ok, value = pcall(require, payload)\
|
|
1253
|
+
return \{ ok = ok, value = value \}\
|
|
1248
1254
|
end\
|
|
1249
1255
|
`
|
|
1250
1256
|
local CLIENT_BRIDGE_SOURCE = `\
|
|
@@ -1268,18 +1274,17 @@ bf.Archivable = false\
|
|
|
1268
1274
|
bf.Parent = ReplicatedStorage\
|
|
1269
1275
|
bf.OnInvoke = function(payload)\
|
|
1270
1276
|
if typeof(payload) ~= "Instance" or not payload:IsA("ModuleScript") then\
|
|
1271
|
-
return false, "payload must be a ModuleScript instance"\
|
|
1277
|
+
return \{ ok = false, value = "payload must be a ModuleScript instance" \}\
|
|
1272
1278
|
end\
|
|
1273
|
-
|
|
1279
|
+
local ok, value = pcall(require, payload)\
|
|
1280
|
+
return \{ ok = ok, value = value \}\
|
|
1274
1281
|
end\
|
|
1275
1282
|
`
|
|
1276
1283
|
-- Stamp written onto each installed bridge Script so we can tell whether the
|
|
1277
|
-
-- bridge currently in the DM was produced by THIS plugin build.
|
|
1278
|
-
-- hash of the actual bridge source plus the plugin version, so ANY
|
|
1279
|
-
-- the source (or a version bump) yields a new stamp
|
|
1280
|
-
--
|
|
1281
|
-
-- keeping a stale bridge that happens to still be present (e.g. one saved into
|
|
1282
|
-
-- the .rbxl from an older build).
|
|
1284
|
+
-- runtime bridge currently in the play DM was produced by THIS plugin build.
|
|
1285
|
+
-- It's a djb2 hash of the actual bridge source plus the plugin version, so ANY
|
|
1286
|
+
-- change to the source (or a version bump) yields a new stamp and triggers a
|
|
1287
|
+
-- runtime refresh instead of keeping a stale bridge.
|
|
1283
1288
|
local STAMP_ATTR = "__MCPBridgeStamp"
|
|
1284
1289
|
local function computeBridgeStamp()
|
|
1285
1290
|
local combined = `{SERVER_BRIDGE_SOURCE}|{CLIENT_BRIDGE_SOURCE}`
|
|
@@ -1287,9 +1292,9 @@ local function computeBridgeStamp()
|
|
|
1287
1292
|
for i = 1, #combined do
|
|
1288
1293
|
h = (h * 33 + (string.byte(combined, i))) % 2147483647
|
|
1289
1294
|
end
|
|
1290
|
-
-- "2.
|
|
1295
|
+
-- "2.16.0" is replaced with the package version at package time
|
|
1291
1296
|
-- (scripts/build-plugin.mjs injectVersion), so a release bump also restamps.
|
|
1292
|
-
return `{tostring(h)}-2.
|
|
1297
|
+
return `{tostring(h)}-2.16.0`
|
|
1293
1298
|
end
|
|
1294
1299
|
local BRIDGE_STAMP = computeBridgeStamp()
|
|
1295
1300
|
local function setSource(scriptInst, source)
|
|
@@ -1305,15 +1310,26 @@ local function setSource(scriptInst, source)
|
|
|
1305
1310
|
scriptInst.Source = source
|
|
1306
1311
|
end
|
|
1307
1312
|
end
|
|
1308
|
-
local function
|
|
1313
|
+
local function findLegacyEditBridges()
|
|
1309
1314
|
local sps = getStarterPlayerScripts()
|
|
1310
1315
|
return {
|
|
1311
1316
|
server = ServerScriptService:FindFirstChild(SERVER_SCRIPT_NAME),
|
|
1312
1317
|
client = if sps then sps:FindFirstChild(CLIENT_SCRIPT_NAME) else nil,
|
|
1313
1318
|
}
|
|
1314
1319
|
end
|
|
1315
|
-
local function
|
|
1316
|
-
local
|
|
1320
|
+
local function destroyIfPresent(parent, name)
|
|
1321
|
+
local existing = parent:FindFirstChild(name)
|
|
1322
|
+
if existing then
|
|
1323
|
+
pcall(function()
|
|
1324
|
+
return existing:Destroy()
|
|
1325
|
+
end)
|
|
1326
|
+
end
|
|
1327
|
+
end
|
|
1328
|
+
local function cleanupLegacyEditBridges()
|
|
1329
|
+
if RunService:IsRunning() then
|
|
1330
|
+
return nil
|
|
1331
|
+
end
|
|
1332
|
+
local _binding = findLegacyEditBridges()
|
|
1317
1333
|
local server = _binding.server
|
|
1318
1334
|
local client = _binding.client
|
|
1319
1335
|
if server then
|
|
@@ -1327,54 +1343,79 @@ local function cleanupBridges()
|
|
|
1327
1343
|
end)
|
|
1328
1344
|
end
|
|
1329
1345
|
end
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
local
|
|
1336
|
-
local
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
end
|
|
1346
|
+
local function serverRuntimeBridgeReady()
|
|
1347
|
+
local scriptInst = ServerScriptService:FindFirstChild(SERVER_SCRIPT_NAME)
|
|
1348
|
+
local bindable = ServerScriptService:FindFirstChild(BRIDGE_NAMES.serverLocal)
|
|
1349
|
+
return scriptInst ~= nil and scriptInst:GetAttribute(STAMP_ATTR) == BRIDGE_STAMP and bindable ~= nil and bindable:IsA("BindableFunction")
|
|
1350
|
+
end
|
|
1351
|
+
local function getPlayerScripts()
|
|
1352
|
+
local localPlayer = Players.LocalPlayer
|
|
1353
|
+
if not localPlayer then
|
|
1354
|
+
return nil
|
|
1355
|
+
end
|
|
1356
|
+
local playerScripts = localPlayer:FindFirstChild("PlayerScripts")
|
|
1357
|
+
if not playerScripts then
|
|
1358
|
+
playerScripts = localPlayer:WaitForChild("PlayerScripts", 5)
|
|
1359
|
+
end
|
|
1360
|
+
return playerScripts
|
|
1361
|
+
end
|
|
1362
|
+
local function clientRuntimeBridgeReady()
|
|
1363
|
+
local playerScripts = getPlayerScripts()
|
|
1364
|
+
if not playerScripts then
|
|
1365
|
+
return false
|
|
1351
1366
|
end
|
|
1352
|
-
|
|
1367
|
+
local scriptInst = playerScripts:FindFirstChild(CLIENT_SCRIPT_NAME)
|
|
1368
|
+
local bindable = ReplicatedStorage:FindFirstChild(BRIDGE_NAMES.clientLocal)
|
|
1369
|
+
return scriptInst ~= nil and scriptInst:GetAttribute(STAMP_ATTR) == BRIDGE_STAMP and bindable ~= nil and bindable:IsA("BindableFunction")
|
|
1353
1370
|
end
|
|
1354
|
-
function
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1371
|
+
local function installServerRuntimeBridge()
|
|
1372
|
+
if serverRuntimeBridgeReady() then
|
|
1373
|
+
return {
|
|
1374
|
+
installed = true,
|
|
1375
|
+
}
|
|
1376
|
+
end
|
|
1360
1377
|
local ok, err = pcall(function()
|
|
1378
|
+
destroyIfPresent(ServerScriptService, SERVER_SCRIPT_NAME)
|
|
1379
|
+
destroyIfPresent(ServerScriptService, BRIDGE_NAMES.serverLocal)
|
|
1361
1380
|
local serverScript = Instance.new("Script")
|
|
1362
1381
|
serverScript.Name = SERVER_SCRIPT_NAME
|
|
1363
|
-
|
|
1364
|
-
-- script. cleanupBridges() removes it from the edit DM when the
|
|
1365
|
-
-- playtest ends.
|
|
1382
|
+
serverScript.Archivable = false
|
|
1366
1383
|
setSource(serverScript, SERVER_BRIDGE_SOURCE)
|
|
1367
1384
|
serverScript:SetAttribute(STAMP_ATTR, BRIDGE_STAMP)
|
|
1368
1385
|
serverScript.Parent = ServerScriptService
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1386
|
+
end)
|
|
1387
|
+
if not ok then
|
|
1388
|
+
return {
|
|
1389
|
+
installed = false,
|
|
1390
|
+
error = tostring(err),
|
|
1391
|
+
}
|
|
1392
|
+
end
|
|
1393
|
+
return {
|
|
1394
|
+
installed = true,
|
|
1395
|
+
}
|
|
1396
|
+
end
|
|
1397
|
+
local function installClientRuntimeBridge()
|
|
1398
|
+
if clientRuntimeBridgeReady() then
|
|
1399
|
+
return {
|
|
1400
|
+
installed = true,
|
|
1401
|
+
}
|
|
1402
|
+
end
|
|
1403
|
+
local playerScripts = getPlayerScripts()
|
|
1404
|
+
if not playerScripts then
|
|
1405
|
+
return {
|
|
1406
|
+
installed = false,
|
|
1407
|
+
error = "Players.LocalPlayer.PlayerScripts not found - cannot install client eval bridge",
|
|
1408
|
+
}
|
|
1409
|
+
end
|
|
1410
|
+
local ok, err = pcall(function()
|
|
1411
|
+
destroyIfPresent(playerScripts, CLIENT_SCRIPT_NAME)
|
|
1412
|
+
destroyIfPresent(ReplicatedStorage, BRIDGE_NAMES.clientLocal)
|
|
1373
1413
|
local clientScript = Instance.new("LocalScript")
|
|
1374
1414
|
clientScript.Name = CLIENT_SCRIPT_NAME
|
|
1415
|
+
clientScript.Archivable = false
|
|
1375
1416
|
setSource(clientScript, CLIENT_BRIDGE_SOURCE)
|
|
1376
1417
|
clientScript:SetAttribute(STAMP_ATTR, BRIDGE_STAMP)
|
|
1377
|
-
clientScript.Parent =
|
|
1418
|
+
clientScript.Parent = playerScripts
|
|
1378
1419
|
end)
|
|
1379
1420
|
if not ok then
|
|
1380
1421
|
return {
|
|
@@ -1386,10 +1427,21 @@ function installBridges()
|
|
|
1386
1427
|
installed = true,
|
|
1387
1428
|
}
|
|
1388
1429
|
end
|
|
1430
|
+
local function ensureRuntimeBridgeInstalled()
|
|
1431
|
+
if not RunService:IsRunning() then
|
|
1432
|
+
return {
|
|
1433
|
+
installed = false,
|
|
1434
|
+
error = "Eval bridges are installed only in running play DataModels",
|
|
1435
|
+
}
|
|
1436
|
+
end
|
|
1437
|
+
if RunService:IsServer() then
|
|
1438
|
+
return installServerRuntimeBridge()
|
|
1439
|
+
end
|
|
1440
|
+
return installClientRuntimeBridge()
|
|
1441
|
+
end
|
|
1389
1442
|
return {
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
installBridges = installBridges,
|
|
1443
|
+
cleanupLegacyEditBridges = cleanupLegacyEditBridges,
|
|
1444
|
+
ensureRuntimeBridgeInstalled = ensureRuntimeBridgeInstalled,
|
|
1393
1445
|
BRIDGE_NAMES = BRIDGE_NAMES,
|
|
1394
1446
|
}
|
|
1395
1447
|
]]></string>
|
|
@@ -2466,6 +2518,160 @@ return {
|
|
|
2466
2518
|
</Properties>
|
|
2467
2519
|
</Item>
|
|
2468
2520
|
<Item class="ModuleScript" referent="9">
|
|
2521
|
+
<Properties>
|
|
2522
|
+
<string name="Name">EvalRuntimeHandlers</string>
|
|
2523
|
+
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
2524
|
+
local TS = require(script.Parent.Parent.Parent.include.RuntimeLib)
|
|
2525
|
+
local _services = TS.import(script, script.Parent.Parent.Parent, "node_modules", "@rbxts", "services")
|
|
2526
|
+
local LogService = _services.LogService
|
|
2527
|
+
local ReplicatedStorage = _services.ReplicatedStorage
|
|
2528
|
+
local RunService = _services.RunService
|
|
2529
|
+
local ServerScriptService = _services.ServerScriptService
|
|
2530
|
+
local _EvalBridges = TS.import(script, script.Parent.Parent, "EvalBridges")
|
|
2531
|
+
local BRIDGE_NAMES = _EvalBridges.BRIDGE_NAMES
|
|
2532
|
+
local ensureRuntimeBridgeInstalled = _EvalBridges.ensureRuntimeBridgeInstalled
|
|
2533
|
+
local LuauExec = TS.import(script, script.Parent.Parent, "LuauExec")
|
|
2534
|
+
local PAYLOAD_INSTANCE_NAME = "__MCPEvalPayload"
|
|
2535
|
+
local function findBridge(config)
|
|
2536
|
+
local bridge = config.service:FindFirstChild(config.bridgeName)
|
|
2537
|
+
return if bridge and bridge:IsA("BindableFunction") then bridge else nil
|
|
2538
|
+
end
|
|
2539
|
+
local function waitForBridge(config, timeoutSec)
|
|
2540
|
+
if timeoutSec == nil then
|
|
2541
|
+
timeoutSec = 2
|
|
2542
|
+
end
|
|
2543
|
+
local deadline = tick() + timeoutSec
|
|
2544
|
+
local bridge = findBridge(config)
|
|
2545
|
+
while not bridge and tick() < deadline do
|
|
2546
|
+
task.wait(0.05)
|
|
2547
|
+
bridge = findBridge(config)
|
|
2548
|
+
end
|
|
2549
|
+
return bridge
|
|
2550
|
+
end
|
|
2551
|
+
local function getBridgeConfig()
|
|
2552
|
+
if not RunService:IsRunning() then
|
|
2553
|
+
return {
|
|
2554
|
+
error = "eval_*_runtime requires a running playtest.",
|
|
2555
|
+
}
|
|
2556
|
+
end
|
|
2557
|
+
if RunService:IsServer() then
|
|
2558
|
+
return {
|
|
2559
|
+
service = ServerScriptService,
|
|
2560
|
+
bridgeName = BRIDGE_NAMES.serverLocal,
|
|
2561
|
+
missingError = "ServerEvalBridge not found. The bridge runs inside the play DM, so a playtest must be running. The bridge installs automatically in the runtime server peer, including for manually-started playtests.",
|
|
2562
|
+
}
|
|
2563
|
+
end
|
|
2564
|
+
return {
|
|
2565
|
+
service = ReplicatedStorage,
|
|
2566
|
+
bridgeName = BRIDGE_NAMES.clientLocal,
|
|
2567
|
+
missingError = "ClientEvalBridge not found. The bridge runs inside the play DM, so a playtest must be running. The bridge installs automatically in the runtime client peer, including for manually-started playtests.",
|
|
2568
|
+
}
|
|
2569
|
+
end
|
|
2570
|
+
local function evalRuntime(requestData)
|
|
2571
|
+
local code = requestData.code
|
|
2572
|
+
if not (code ~= "" and code) or code == "" then
|
|
2573
|
+
return {
|
|
2574
|
+
error = "Code is required",
|
|
2575
|
+
}
|
|
2576
|
+
end
|
|
2577
|
+
local config = getBridgeConfig()
|
|
2578
|
+
if config.error ~= nil then
|
|
2579
|
+
return {
|
|
2580
|
+
bridge = "missing",
|
|
2581
|
+
error = config.error,
|
|
2582
|
+
}
|
|
2583
|
+
end
|
|
2584
|
+
local bridge = findBridge(config)
|
|
2585
|
+
if not bridge then
|
|
2586
|
+
local install = ensureRuntimeBridgeInstalled()
|
|
2587
|
+
if not install.installed then
|
|
2588
|
+
return {
|
|
2589
|
+
bridge = "missing",
|
|
2590
|
+
error = `{config.missingError} Runtime bridge install failed: {install.error}`,
|
|
2591
|
+
}
|
|
2592
|
+
end
|
|
2593
|
+
bridge = waitForBridge(config)
|
|
2594
|
+
end
|
|
2595
|
+
if not bridge then
|
|
2596
|
+
return {
|
|
2597
|
+
bridge = "missing",
|
|
2598
|
+
error = `{config.missingError} Runtime bridge was installed but did not become ready.`,
|
|
2599
|
+
}
|
|
2600
|
+
end
|
|
2601
|
+
local m = Instance.new("ModuleScript")
|
|
2602
|
+
m.Name = PAYLOAD_INSTANCE_NAME
|
|
2603
|
+
local userLines = LuauExec.countLines(code)
|
|
2604
|
+
local wrapped = LuauExec.buildWrapper(code, PAYLOAD_INSTANCE_NAME)
|
|
2605
|
+
local okSet, setErr = pcall(function()
|
|
2606
|
+
m.Source = wrapped
|
|
2607
|
+
end)
|
|
2608
|
+
if not okSet then
|
|
2609
|
+
m:Destroy()
|
|
2610
|
+
return {
|
|
2611
|
+
bridge = "ok",
|
|
2612
|
+
ok = false,
|
|
2613
|
+
error = `ModuleScript Source set failed: {tostring(setErr)}`,
|
|
2614
|
+
}
|
|
2615
|
+
end
|
|
2616
|
+
m.Parent = game:GetService("Workspace")
|
|
2617
|
+
local historyStart = #LogService:GetLogHistory()
|
|
2618
|
+
local invokeOk, invokeResult = pcall(function()
|
|
2619
|
+
return bridge:Invoke(m)
|
|
2620
|
+
end)
|
|
2621
|
+
m:Destroy()
|
|
2622
|
+
if not invokeOk then
|
|
2623
|
+
return {
|
|
2624
|
+
bridge = "ok",
|
|
2625
|
+
ok = false,
|
|
2626
|
+
error = tostring(invokeResult),
|
|
2627
|
+
}
|
|
2628
|
+
end
|
|
2629
|
+
if not (type(invokeResult) == "table") then
|
|
2630
|
+
return {
|
|
2631
|
+
bridge = "ok",
|
|
2632
|
+
ok = false,
|
|
2633
|
+
error = `Eval bridge returned invalid result: {tostring(invokeResult)}`,
|
|
2634
|
+
}
|
|
2635
|
+
end
|
|
2636
|
+
local bridgeResult = invokeResult
|
|
2637
|
+
if bridgeResult.ok ~= true then
|
|
2638
|
+
return {
|
|
2639
|
+
bridge = "ok",
|
|
2640
|
+
ok = false,
|
|
2641
|
+
error = LuauExec.recoverPayloadRequireError(bridgeResult.value, userLines, PAYLOAD_INSTANCE_NAME, historyStart),
|
|
2642
|
+
}
|
|
2643
|
+
end
|
|
2644
|
+
local inner = bridgeResult.value
|
|
2645
|
+
if not (type(inner) == "table") then
|
|
2646
|
+
return {
|
|
2647
|
+
bridge = "ok",
|
|
2648
|
+
ok = true,
|
|
2649
|
+
result = if inner == nil then nil else LuauExec.formatReturnValue(inner),
|
|
2650
|
+
}
|
|
2651
|
+
end
|
|
2652
|
+
local r = inner
|
|
2653
|
+
local ok = r.ok == true
|
|
2654
|
+
local _object = {
|
|
2655
|
+
bridge = "ok",
|
|
2656
|
+
ok = ok,
|
|
2657
|
+
result = if ok and r.value ~= nil then LuauExec.formatReturnValue(r.value) else nil,
|
|
2658
|
+
error = if not ok then tostring(r.value) else nil,
|
|
2659
|
+
}
|
|
2660
|
+
local _left = "output"
|
|
2661
|
+
local _condition = r.output
|
|
2662
|
+
if _condition == nil then
|
|
2663
|
+
_condition = {}
|
|
2664
|
+
end
|
|
2665
|
+
_object[_left] = _condition
|
|
2666
|
+
return _object
|
|
2667
|
+
end
|
|
2668
|
+
return {
|
|
2669
|
+
evalRuntime = evalRuntime,
|
|
2670
|
+
}
|
|
2671
|
+
]]></string>
|
|
2672
|
+
</Properties>
|
|
2673
|
+
</Item>
|
|
2674
|
+
<Item class="ModuleScript" referent="10">
|
|
2469
2675
|
<Properties>
|
|
2470
2676
|
<string name="Name">InputHandlers</string>
|
|
2471
2677
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -2665,7 +2871,7 @@ return {
|
|
|
2665
2871
|
]]></string>
|
|
2666
2872
|
</Properties>
|
|
2667
2873
|
</Item>
|
|
2668
|
-
<Item class="ModuleScript" referent="
|
|
2874
|
+
<Item class="ModuleScript" referent="11">
|
|
2669
2875
|
<Properties>
|
|
2670
2876
|
<string name="Name">InstanceHandlers</string>
|
|
2671
2877
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -3172,7 +3378,7 @@ return {
|
|
|
3172
3378
|
]]></string>
|
|
3173
3379
|
</Properties>
|
|
3174
3380
|
</Item>
|
|
3175
|
-
<Item class="ModuleScript" referent="
|
|
3381
|
+
<Item class="ModuleScript" referent="12">
|
|
3176
3382
|
<Properties>
|
|
3177
3383
|
<string name="Name">LogHandlers</string>
|
|
3178
3384
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -3182,16 +3388,15 @@ local function getRuntimeLogs(requestData)
|
|
|
3182
3388
|
local since = requestData.since
|
|
3183
3389
|
local tail = requestData.tail
|
|
3184
3390
|
local filter = requestData.filter
|
|
3185
|
-
--
|
|
3186
|
-
--
|
|
3187
|
-
--
|
|
3188
|
-
|
|
3189
|
-
local peer = RuntimeLogBuffer.detectPeer()
|
|
3391
|
+
-- This is the buffer that captured the LogService event, not necessarily
|
|
3392
|
+
-- the script-origin peer. Ordinary playtests share/reflect logs across
|
|
3393
|
+
-- edit/server/client LogService buffers.
|
|
3394
|
+
local capturedBy = RuntimeLogBuffer.detectPeer()
|
|
3190
3395
|
return RuntimeLogBuffer.query({
|
|
3191
3396
|
since = since,
|
|
3192
3397
|
tail = tail,
|
|
3193
3398
|
filter = filter,
|
|
3194
|
-
},
|
|
3399
|
+
}, capturedBy)
|
|
3195
3400
|
end
|
|
3196
3401
|
return {
|
|
3197
3402
|
getRuntimeLogs = getRuntimeLogs,
|
|
@@ -3199,7 +3404,7 @@ return {
|
|
|
3199
3404
|
]]></string>
|
|
3200
3405
|
</Properties>
|
|
3201
3406
|
</Item>
|
|
3202
|
-
<Item class="ModuleScript" referent="
|
|
3407
|
+
<Item class="ModuleScript" referent="13">
|
|
3203
3408
|
<Properties>
|
|
3204
3409
|
<string name="Name">MemoryHandlers</string>
|
|
3205
3410
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -3267,7 +3472,7 @@ return {
|
|
|
3267
3472
|
]]></string>
|
|
3268
3473
|
</Properties>
|
|
3269
3474
|
</Item>
|
|
3270
|
-
<Item class="ModuleScript" referent="
|
|
3475
|
+
<Item class="ModuleScript" referent="14">
|
|
3271
3476
|
<Properties>
|
|
3272
3477
|
<string name="Name">MetadataHandlers</string>
|
|
3273
3478
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -3806,7 +4011,7 @@ return {
|
|
|
3806
4011
|
]]></string>
|
|
3807
4012
|
</Properties>
|
|
3808
4013
|
</Item>
|
|
3809
|
-
<Item class="ModuleScript" referent="
|
|
4014
|
+
<Item class="ModuleScript" referent="15">
|
|
3810
4015
|
<Properties>
|
|
3811
4016
|
<string name="Name">PropertyHandlers</string>
|
|
3812
4017
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -4058,7 +4263,7 @@ return {
|
|
|
4058
4263
|
]]></string>
|
|
4059
4264
|
</Properties>
|
|
4060
4265
|
</Item>
|
|
4061
|
-
<Item class="ModuleScript" referent="
|
|
4266
|
+
<Item class="ModuleScript" referent="16">
|
|
4062
4267
|
<Properties>
|
|
4063
4268
|
<string name="Name">QueryHandlers</string>
|
|
4064
4269
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -5100,7 +5305,7 @@ return {
|
|
|
5100
5305
|
]]></string>
|
|
5101
5306
|
</Properties>
|
|
5102
5307
|
</Item>
|
|
5103
|
-
<Item class="ModuleScript" referent="
|
|
5308
|
+
<Item class="ModuleScript" referent="17">
|
|
5104
5309
|
<Properties>
|
|
5105
5310
|
<string name="Name">SceneAnalysisHandlers</string>
|
|
5106
5311
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -5349,7 +5554,7 @@ return {
|
|
|
5349
5554
|
]]></string>
|
|
5350
5555
|
</Properties>
|
|
5351
5556
|
</Item>
|
|
5352
|
-
<Item class="ModuleScript" referent="
|
|
5557
|
+
<Item class="ModuleScript" referent="18">
|
|
5353
5558
|
<Properties>
|
|
5354
5559
|
<string name="Name">ScriptHandlers</string>
|
|
5355
5560
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -6045,7 +6250,7 @@ return {
|
|
|
6045
6250
|
]]></string>
|
|
6046
6251
|
</Properties>
|
|
6047
6252
|
</Item>
|
|
6048
|
-
<Item class="ModuleScript" referent="
|
|
6253
|
+
<Item class="ModuleScript" referent="19">
|
|
6049
6254
|
<Properties>
|
|
6050
6255
|
<string name="Name">SerializationHandlers</string>
|
|
6051
6256
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -6231,7 +6436,7 @@ return {
|
|
|
6231
6436
|
]]></string>
|
|
6232
6437
|
</Properties>
|
|
6233
6438
|
</Item>
|
|
6234
|
-
<Item class="ModuleScript" referent="
|
|
6439
|
+
<Item class="ModuleScript" referent="20">
|
|
6235
6440
|
<Properties>
|
|
6236
6441
|
<string name="Name">TestHandlers</string>
|
|
6237
6442
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -6241,9 +6446,6 @@ local HttpService = _services.HttpService
|
|
|
6241
6446
|
local LogService = _services.LogService
|
|
6242
6447
|
local Players = _services.Players
|
|
6243
6448
|
local RunService = _services.RunService
|
|
6244
|
-
local _EvalBridges = TS.import(script, script.Parent.Parent, "EvalBridges")
|
|
6245
|
-
local installBridges = _EvalBridges.installBridges
|
|
6246
|
-
local ensureBridgesInstalled = _EvalBridges.ensureBridgesInstalled
|
|
6247
6449
|
local StopPlayMonitor = TS.import(script, script.Parent.Parent, "StopPlayMonitor")
|
|
6248
6450
|
local StudioTestService = game:GetService("StudioTestService")
|
|
6249
6451
|
local ServerScriptService = game:GetService("ServerScriptService")
|
|
@@ -6430,9 +6632,8 @@ local function startPlaytest(requestData)
|
|
|
6430
6632
|
logConnection = nil
|
|
6431
6633
|
end
|
|
6432
6634
|
cleanupStopListener()
|
|
6433
|
-
--
|
|
6434
|
-
--
|
|
6435
|
-
-- EvalBridges.ts lifecycle comment.
|
|
6635
|
+
-- Runtime eval bridges are created by the play server/client plugin
|
|
6636
|
+
-- peers and disappear with the play DataModels.
|
|
6436
6637
|
end
|
|
6437
6638
|
if testRunning then
|
|
6438
6639
|
return {
|
|
@@ -6475,14 +6676,6 @@ local function startPlaytest(requestData)
|
|
|
6475
6676
|
if not injected then
|
|
6476
6677
|
warn(`[MCP] Failed to inject stop listener: {injErr}`)
|
|
6477
6678
|
end
|
|
6478
|
-
-- Force-refresh the game-VM eval bridges (ServerEvalBridge + ClientEvalBridge)
|
|
6479
|
-
-- right before cloning so the play DMs get the current source. They also
|
|
6480
|
-
-- live permanently in the edit DM (installed on connect) so manually-started
|
|
6481
|
-
-- playtests get them too; here we just ensure they're fresh.
|
|
6482
|
-
local bridgeInstall = installBridges()
|
|
6483
|
-
if not bridgeInstall.installed then
|
|
6484
|
-
warn(`[MCP] Eval bridge install failed: {bridgeInstall.error}`)
|
|
6485
|
-
end
|
|
6486
6679
|
task.spawn(function()
|
|
6487
6680
|
local ok, result = pcall(function()
|
|
6488
6681
|
if mode == "play" then
|
|
@@ -6501,21 +6694,11 @@ local function startPlaytest(requestData)
|
|
|
6501
6694
|
end
|
|
6502
6695
|
testRunning = false
|
|
6503
6696
|
cleanupStopListener()
|
|
6504
|
-
-- Eval bridges persist in the edit DM (see EvalBridges.ts) — do not
|
|
6505
|
-
-- clean up here, so the next manual playtest still gets them.
|
|
6506
|
-
ensureBridgesInstalled()
|
|
6507
6697
|
end)
|
|
6508
6698
|
local response = {
|
|
6509
6699
|
success = true,
|
|
6510
6700
|
message = `Playtest started in {mode} mode.`,
|
|
6511
6701
|
}
|
|
6512
|
-
-- Only mention eval bridges when they failed — when they're fine, the
|
|
6513
|
-
-- detail is noise. eval_server_runtime / eval_client_runtime will surface
|
|
6514
|
-
-- their own clear errors if the caller tries to use them after a failed
|
|
6515
|
-
-- install.
|
|
6516
|
-
if not bridgeInstall.installed then
|
|
6517
|
-
response.evalBridgesError = bridgeInstall.error
|
|
6518
|
-
end
|
|
6519
6702
|
return response
|
|
6520
6703
|
end
|
|
6521
6704
|
local function stopPlaytest(_requestData)
|
|
@@ -6610,10 +6793,6 @@ local function multiplayerTestStart(requestData)
|
|
|
6610
6793
|
end
|
|
6611
6794
|
local testArgs = if requestData.testArgs ~= nil then requestData.testArgs else {}
|
|
6612
6795
|
local testId = HttpService:GenerateGUID(false)
|
|
6613
|
-
local bridgeInstall = installBridges()
|
|
6614
|
-
if not bridgeInstall.installed then
|
|
6615
|
-
warn(`[MCP] Eval bridge install failed: {bridgeInstall.error}`)
|
|
6616
|
-
end
|
|
6617
6796
|
multiplayerState = {
|
|
6618
6797
|
phase = "starting",
|
|
6619
6798
|
testId = testId,
|
|
@@ -6637,7 +6816,6 @@ local function multiplayerTestStart(requestData)
|
|
|
6637
6816
|
multiplayerState.result = nil
|
|
6638
6817
|
multiplayerState.error = tostring(result)
|
|
6639
6818
|
end
|
|
6640
|
-
ensureBridgesInstalled()
|
|
6641
6819
|
end)
|
|
6642
6820
|
local response = {
|
|
6643
6821
|
success = true,
|
|
@@ -6647,9 +6825,6 @@ local function multiplayerTestStart(requestData)
|
|
|
6647
6825
|
numPlayers = numPlayers,
|
|
6648
6826
|
testArgs = testArgs,
|
|
6649
6827
|
}
|
|
6650
|
-
if not bridgeInstall.installed then
|
|
6651
|
-
response.evalBridgesError = bridgeInstall.error
|
|
6652
|
-
end
|
|
6653
6828
|
return response
|
|
6654
6829
|
end
|
|
6655
6830
|
local function multiplayerTestState(_requestData)
|
|
@@ -6864,7 +7039,7 @@ return {
|
|
|
6864
7039
|
</Properties>
|
|
6865
7040
|
</Item>
|
|
6866
7041
|
</Item>
|
|
6867
|
-
<Item class="ModuleScript" referent="
|
|
7042
|
+
<Item class="ModuleScript" referent="21">
|
|
6868
7043
|
<Properties>
|
|
6869
7044
|
<string name="Name">LuauExec</string>
|
|
6870
7045
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -6873,10 +7048,12 @@ return {
|
|
|
6873
7048
|
-- and the play-client peer (ClientBroker.handleExecuteLuau). Three things this
|
|
6874
7049
|
-- module owns:
|
|
6875
7050
|
--
|
|
6876
|
-
-- 1. The IIFE wrapper that captures print/warn,
|
|
6877
|
-
--
|
|
6878
|
-
-- always returns
|
|
6879
|
-
--
|
|
7051
|
+
-- 1. The IIFE wrapper that captures print/warn, wraps require() so nested
|
|
7052
|
+
-- ModuleScript load failures can recover the real LogService diagnostic,
|
|
7053
|
+
-- runs user code in xpcall, and always returns { ok, value, output } so
|
|
7054
|
+
-- the ModuleScript itself always returns exactly one value (otherwise
|
|
7055
|
+
-- `print("hi")` with no return would fail with "Module code did not
|
|
7056
|
+
-- return exactly one value").
|
|
6880
7057
|
--
|
|
6881
7058
|
-- 2. The loadstring-then-ModuleScript-require fallback, with the parse-error
|
|
6882
7059
|
-- recovery hack that pulls the real diagnostic from LogService.
|
|
@@ -6894,14 +7071,14 @@ return {
|
|
|
6894
7071
|
local HttpService = game:GetService("HttpService")
|
|
6895
7072
|
local LogService = game:GetService("LogService")
|
|
6896
7073
|
local PAYLOAD_INSTANCE_NAME = "__MCPExecLuauPayload"
|
|
6897
|
-
local
|
|
7074
|
+
local REQUIRE_GENERIC_ERROR = "Requested module experienced an error while loading"
|
|
6898
7075
|
-- Number of lines the wrapper emits BEFORE the first line of user code.
|
|
6899
7076
|
-- Used both inside the wrapper (Luau __mcp_LINE_OFFSET) and on the TS side
|
|
6900
7077
|
-- (remapPayloadLines, for compile errors recovered from LogService) so user
|
|
6901
7078
|
-- code errors report user-relative line numbers instead of the inflated
|
|
6902
|
-
-- "line
|
|
6903
|
-
-- prefix lines, update this constant
|
|
6904
|
-
local WRAPPER_LINE_OFFSET =
|
|
7079
|
+
-- "line 49" the wrapper would otherwise expose. If you reorder buildWrapper's
|
|
7080
|
+
-- prefix lines, update this constant.
|
|
7081
|
+
local WRAPPER_LINE_OFFSET = 84
|
|
6905
7082
|
-- Count source lines so the wrapper can filter traceback frames that fall
|
|
6906
7083
|
-- outside the user code range (the wrapper's own preamble/postamble lines).
|
|
6907
7084
|
local function countLines(s)
|
|
@@ -6926,20 +7103,31 @@ local function countLines(s)
|
|
|
6926
7103
|
end
|
|
6927
7104
|
return n
|
|
6928
7105
|
end
|
|
6929
|
-
local function
|
|
7106
|
+
local function luaPatternEscape(s)
|
|
7107
|
+
local escaped = string.gsub(s, "([^%w])", "%%%1")
|
|
7108
|
+
return escaped
|
|
7109
|
+
end
|
|
7110
|
+
local function buildWrapper(code, payloadInstanceName)
|
|
7111
|
+
if payloadInstanceName == nil then
|
|
7112
|
+
payloadInstanceName = PAYLOAD_INSTANCE_NAME
|
|
7113
|
+
end
|
|
6930
7114
|
-- If you reorder the prefix lines below, update WRAPPER_LINE_OFFSET to
|
|
6931
7115
|
-- match the number of lines emitted BEFORE the ${code} substitution.
|
|
6932
7116
|
-- The constant is mirrored inside the wrapper (__mcp_LINE_OFFSET) and
|
|
6933
7117
|
-- used by remapPayloadLines on the TS side.
|
|
6934
7118
|
local userLines = countLines(code)
|
|
7119
|
+
local payloadPattern = luaPatternEscape(payloadInstanceName)
|
|
6935
7120
|
return `return ((function()\
|
|
6936
7121
|
\tlocal __mcp_traceback\
|
|
6937
7122
|
\tlocal __mcp_remap\
|
|
6938
7123
|
\tlocal __mcp_LINE_OFFSET = {WRAPPER_LINE_OFFSET}\
|
|
6939
7124
|
\tlocal __mcp_USER_LINES = {userLines}\
|
|
7125
|
+
\tlocal __mcp_LogService = game:GetService("LogService")\
|
|
7126
|
+
\tlocal __mcp_REQUIRE_GENERIC = "{REQUIRE_GENERIC_ERROR}"\
|
|
6940
7127
|
\tlocal __mcp_output = \{\}\
|
|
6941
7128
|
\tlocal __mcp_real_print = print\
|
|
6942
7129
|
\tlocal __mcp_real_warn = warn\
|
|
7130
|
+
\tlocal __mcp_real_require = require\
|
|
6943
7131
|
\tlocal print = function(...)\
|
|
6944
7132
|
\t\t__mcp_real_print(...)\
|
|
6945
7133
|
\t\tlocal args = \{...\}\
|
|
@@ -6954,6 +7142,64 @@ local function buildWrapper(code)
|
|
|
6954
7142
|
\t\tfor i, a in ipairs(args) do parts[i] = tostring(a) end\
|
|
6955
7143
|
\t\ttable.insert(__mcp_output, "[warn] " .. table.concat(parts, "\\t"))\
|
|
6956
7144
|
\tend\
|
|
7145
|
+
\tlocal function __mcp_is_stack_noise(msg)\
|
|
7146
|
+
\t\treturn msg == "Stack Begin" or msg == "Stack End" or string.sub(msg, 1, 8) == "Script '"\
|
|
7147
|
+
\tend\
|
|
7148
|
+
\tlocal function __mcp_is_actionable_require_log(entry)\
|
|
7149
|
+
\t\tif not entry or entry.messageType ~= Enum.MessageType.MessageError then return false end\
|
|
7150
|
+
\t\tlocal msg = tostring(entry.message)\
|
|
7151
|
+
\t\treturn msg ~= __mcp_REQUIRE_GENERIC and not __mcp_is_stack_noise(msg)\
|
|
7152
|
+
\tend\
|
|
7153
|
+
\tlocal function __mcp_entry_mentions_module(entry, module_path)\
|
|
7154
|
+
\t\tif not entry or not module_path or module_path == "" then return false end\
|
|
7155
|
+
\t\treturn string.find(tostring(entry.message), module_path, 1, true) ~= nil\
|
|
7156
|
+
\tend\
|
|
7157
|
+
\tlocal function __mcp_prior_module_error(hist, module_path)\
|
|
7158
|
+
\t\tif not module_path or module_path == "" then return nil end\
|
|
7159
|
+
\t\tfor i = #hist, 1, -1 do\
|
|
7160
|
+
\t\t\tlocal entry = hist[i]\
|
|
7161
|
+
\t\t\tif __mcp_entry_mentions_module(entry, module_path) then\
|
|
7162
|
+
\t\t\t\tif __mcp_is_actionable_require_log(entry) then\
|
|
7163
|
+
\t\t\t\t\treturn tostring(entry.message)\
|
|
7164
|
+
\t\t\t\tend\
|
|
7165
|
+
\t\t\t\tfor j = i - 1, math.max(1, i - 6), -1 do\
|
|
7166
|
+
\t\t\t\t\tlocal previous = hist[j]\
|
|
7167
|
+
\t\t\t\t\tif __mcp_is_actionable_require_log(previous) then\
|
|
7168
|
+
\t\t\t\t\t\treturn tostring(previous.message)\
|
|
7169
|
+
\t\t\t\t\tend\
|
|
7170
|
+
\t\t\t\tend\
|
|
7171
|
+
\t\t\tend\
|
|
7172
|
+
\t\tend\
|
|
7173
|
+
\t\treturn nil\
|
|
7174
|
+
\tend\
|
|
7175
|
+
\tlocal function __mcp_recover_require_error(err, history_start, module)\
|
|
7176
|
+
\t\tlocal err_msg = tostring(err)\
|
|
7177
|
+
\t\tif err_msg ~= __mcp_REQUIRE_GENERIC then return err_msg end\
|
|
7178
|
+
\t\tlocal module_path\
|
|
7179
|
+
\t\tif typeof(module) == "Instance" then\
|
|
7180
|
+
\t\t\tlocal ok_path, path = pcall(function()\
|
|
7181
|
+
\t\t\t\treturn module:GetFullName()\
|
|
7182
|
+
\t\t\tend)\
|
|
7183
|
+
\t\t\tif ok_path then module_path = path end\
|
|
7184
|
+
\t\tend\
|
|
7185
|
+
\t\ttask.wait(0.05)\
|
|
7186
|
+
\t\tlocal hist = __mcp_LogService:GetLogHistory()\
|
|
7187
|
+
\t\tfor i = #hist, history_start + 1, -1 do\
|
|
7188
|
+
\t\t\tlocal entry = hist[i]\
|
|
7189
|
+
\t\t\tif __mcp_is_actionable_require_log(entry) then\
|
|
7190
|
+
\t\t\t\treturn tostring(entry.message)\
|
|
7191
|
+
\t\t\tend\
|
|
7192
|
+
\t\tend\
|
|
7193
|
+
\t\tlocal prior = __mcp_prior_module_error(hist, module_path)\
|
|
7194
|
+
\t\tif prior then return prior end\
|
|
7195
|
+
\t\treturn err_msg\
|
|
7196
|
+
\tend\
|
|
7197
|
+
\tlocal function require(module)\
|
|
7198
|
+
\t\tlocal history_start = #__mcp_LogService:GetLogHistory()\
|
|
7199
|
+
\t\tlocal ok, value = pcall(__mcp_real_require, module)\
|
|
7200
|
+
\t\tif ok then return value end\
|
|
7201
|
+
\t\terror(__mcp_recover_require_error(value, history_start, module), 0)\
|
|
7202
|
+
\tend\
|
|
6957
7203
|
\tlocal function __mcp_run()\
|
|
6958
7204
|
{code}\
|
|
6959
7205
|
\tend\
|
|
@@ -6964,15 +7210,20 @@ local function buildWrapper(code)
|
|
|
6964
7210
|
\t\t-- Subtract LINE_OFFSET to get the user-relative number, then clamp.\
|
|
6965
7211
|
\t\t-- Clamping matters for unclosed constructs ("local x = (") where the\
|
|
6966
7212
|
\t\t-- parser keeps reading into wrapper postamble and reports a payload\
|
|
6967
|
-
\t\t-- line past user EOF. Without clamping
|
|
6968
|
-
\t\t--
|
|
7213
|
+
\t\t-- line past user EOF. Without clamping, that frames wrapper postamble\
|
|
7214
|
+
\t\t-- as user code.\
|
|
6969
7215
|
\t\tlocal function __mcp_user_line(payload_n)\
|
|
6970
7216
|
\t\t\tlocal user_n = payload_n - __mcp_LINE_OFFSET\
|
|
6971
7217
|
\t\t\tif user_n < 1 then return "1" end\
|
|
6972
7218
|
\t\t\tif user_n > __mcp_USER_LINES then return tostring(__mcp_USER_LINES) .. " (at end of input)" end\
|
|
6973
7219
|
\t\t\treturn tostring(user_n)\
|
|
6974
7220
|
\t\tend\
|
|
6975
|
-
\t\ts = string.gsub(s, "
|
|
7221
|
+
\t\ts = string.gsub(s, "Workspace%.{payloadPattern}:(%d+)", function(num)\
|
|
7222
|
+
\t\t\tlocal n = tonumber(num)\
|
|
7223
|
+
\t\t\tif n then return "user_code:" .. __mcp_user_line(n) end\
|
|
7224
|
+
\t\t\treturn "user_code:" .. num\
|
|
7225
|
+
\t\tend)\
|
|
7226
|
+
\t\ts = string.gsub(s, "{payloadPattern}:(%d+)", function(num)\
|
|
6976
7227
|
\t\t\tlocal n = tonumber(num)\
|
|
6977
7228
|
\t\t\tif n then return "user_code:" .. __mcp_user_line(n) end\
|
|
6978
7229
|
\t\t\treturn "user_code:" .. num\
|
|
@@ -7022,7 +7273,10 @@ end
|
|
|
7022
7273
|
-- pulling the real compile-error diagnostic out of LogService — that error
|
|
7023
7274
|
-- references the payload module's line number directly, and never passes
|
|
7024
7275
|
-- through the IIFE's runtime wrapper.
|
|
7025
|
-
local function remapPayloadLines(s, userLines)
|
|
7276
|
+
local function remapPayloadLines(s, userLines, payloadInstanceName)
|
|
7277
|
+
if payloadInstanceName == nil then
|
|
7278
|
+
payloadInstanceName = PAYLOAD_INSTANCE_NAME
|
|
7279
|
+
end
|
|
7026
7280
|
-- Mirror of the Lua __mcp_remap inside the wrapper, for paths that
|
|
7027
7281
|
-- don't pass through the IIFE (compile errors recovered from
|
|
7028
7282
|
-- LogService, the immediate loadstring compileError surface). Same
|
|
@@ -7040,8 +7294,9 @@ local function remapPayloadLines(s, userLines)
|
|
|
7040
7294
|
end
|
|
7041
7295
|
return tostring(u)
|
|
7042
7296
|
end
|
|
7297
|
+
local payloadPattern = luaPatternEscape(payloadInstanceName)
|
|
7043
7298
|
local out = s
|
|
7044
|
-
local a = string.gsub(out,
|
|
7299
|
+
local a = string.gsub(out, `Workspace%.{payloadPattern}:(%d+)`, function(num)
|
|
7045
7300
|
local n = tonumber(num)
|
|
7046
7301
|
if n ~= nil then
|
|
7047
7302
|
return `user_code:{userLine(n)}`
|
|
@@ -7049,7 +7304,7 @@ local function remapPayloadLines(s, userLines)
|
|
|
7049
7304
|
return `user_code:{num}`
|
|
7050
7305
|
end)
|
|
7051
7306
|
out = a
|
|
7052
|
-
local b = string.gsub(out,
|
|
7307
|
+
local b = string.gsub(out, `{payloadPattern}:(%d+)`, function(num)
|
|
7053
7308
|
local n = tonumber(num)
|
|
7054
7309
|
if n ~= nil then
|
|
7055
7310
|
return `user_code:{userLine(n)}`
|
|
@@ -7057,8 +7312,16 @@ local function remapPayloadLines(s, userLines)
|
|
|
7057
7312
|
return `user_code:{num}`
|
|
7058
7313
|
end)
|
|
7059
7314
|
out = b
|
|
7060
|
-
|
|
7315
|
+
local c = string.gsub(out, '%[string "[^"]+"%]:(%d+)', function(num)
|
|
7316
|
+
local n = tonumber(num)
|
|
7317
|
+
if n ~= nil then
|
|
7318
|
+
return `user_code:{userLine(n)}`
|
|
7319
|
+
end
|
|
7320
|
+
return `user_code:{num}`
|
|
7321
|
+
end)
|
|
7322
|
+
return c
|
|
7061
7323
|
end
|
|
7324
|
+
local recoverPayloadRequireError
|
|
7062
7325
|
local function runViaModuleScript(wrapped, userLines)
|
|
7063
7326
|
local m = Instance.new("ModuleScript")
|
|
7064
7327
|
m.Name = PAYLOAD_INSTANCE_NAME
|
|
@@ -7078,26 +7341,11 @@ local function runViaModuleScript(wrapped, userLines)
|
|
|
7078
7341
|
end)
|
|
7079
7342
|
m:Destroy()
|
|
7080
7343
|
if not okReq then
|
|
7081
|
-
local errMsg = tostring(reqResult)
|
|
7082
|
-
-- pcall(require, m) collapses parse/compile failures into the canned
|
|
7083
|
-
-- engine string. The real diagnostic was emitted to LogService on the
|
|
7084
|
-
-- next engine frame — give it ~50ms to land then scan backward.
|
|
7085
|
-
if errMsg == "Requested module experienced an error while loading" then
|
|
7086
|
-
task.wait(0.05)
|
|
7087
|
-
local hist = LogService:GetLogHistory()
|
|
7088
|
-
for i = #hist - 1, 0, -1 do
|
|
7089
|
-
local e = hist[i + 1]
|
|
7090
|
-
if e.messageType == Enum.MessageType.MessageError and string.sub(e.message, 1, #PAYLOAD_PATH_PREFIX) == PAYLOAD_PATH_PREFIX then
|
|
7091
|
-
errMsg = e.message
|
|
7092
|
-
break
|
|
7093
|
-
end
|
|
7094
|
-
end
|
|
7095
|
-
end
|
|
7096
7344
|
-- Compile errors reference the payload module's line number directly
|
|
7097
7345
|
-- — remap + clamp to user-relative line numbers so `local x = 1 +`
|
|
7098
7346
|
-- reports :1: instead of :23:, and reports the clamp annotation
|
|
7099
7347
|
-- when the parser ran off the end of user code into wrapper code.
|
|
7100
|
-
error(
|
|
7348
|
+
error(recoverPayloadRequireError(reqResult, userLines, PAYLOAD_INSTANCE_NAME), 0)
|
|
7101
7349
|
end
|
|
7102
7350
|
return reqResult
|
|
7103
7351
|
end
|
|
@@ -7124,6 +7372,44 @@ local function formatReturnValue(value)
|
|
|
7124
7372
|
end
|
|
7125
7373
|
return tostring(value)
|
|
7126
7374
|
end
|
|
7375
|
+
function recoverPayloadRequireError(err, userLines, payloadInstanceName, historyStart)
|
|
7376
|
+
if payloadInstanceName == nil then
|
|
7377
|
+
payloadInstanceName = PAYLOAD_INSTANCE_NAME
|
|
7378
|
+
end
|
|
7379
|
+
if historyStart == nil then
|
|
7380
|
+
historyStart = 0
|
|
7381
|
+
end
|
|
7382
|
+
local errMsg = tostring(err)
|
|
7383
|
+
-- pcall(require, m) collapses parse/compile failures into the canned
|
|
7384
|
+
-- engine string. The real diagnostic is emitted to LogService on the
|
|
7385
|
+
-- next engine frame — give it ~50ms to land then scan backward.
|
|
7386
|
+
if errMsg == REQUIRE_GENERIC_ERROR then
|
|
7387
|
+
task.wait(0.05)
|
|
7388
|
+
local payloadPathPrefix = `Workspace.{payloadInstanceName}:`
|
|
7389
|
+
local hist = LogService:GetLogHistory()
|
|
7390
|
+
local start = math.max(0, historyStart)
|
|
7391
|
+
do
|
|
7392
|
+
local i = #hist - 1
|
|
7393
|
+
local _shouldIncrement = false
|
|
7394
|
+
while true do
|
|
7395
|
+
if _shouldIncrement then
|
|
7396
|
+
i -= 1
|
|
7397
|
+
else
|
|
7398
|
+
_shouldIncrement = true
|
|
7399
|
+
end
|
|
7400
|
+
if not (i >= start) then
|
|
7401
|
+
break
|
|
7402
|
+
end
|
|
7403
|
+
local e = hist[i + 1]
|
|
7404
|
+
if e.messageType == Enum.MessageType.MessageError and string.sub(e.message, 1, #payloadPathPrefix) == payloadPathPrefix then
|
|
7405
|
+
errMsg = e.message
|
|
7406
|
+
break
|
|
7407
|
+
end
|
|
7408
|
+
end
|
|
7409
|
+
end
|
|
7410
|
+
end
|
|
7411
|
+
return remapPayloadLines(errMsg, userLines, payloadInstanceName)
|
|
7412
|
+
end
|
|
7127
7413
|
local function execute(code)
|
|
7128
7414
|
if not (code ~= "" and code) or code == "" then
|
|
7129
7415
|
return {
|
|
@@ -7177,12 +7463,17 @@ local function execute(code)
|
|
|
7177
7463
|
}
|
|
7178
7464
|
end
|
|
7179
7465
|
return {
|
|
7466
|
+
buildWrapper = buildWrapper,
|
|
7467
|
+
countLines = countLines,
|
|
7180
7468
|
execute = execute,
|
|
7469
|
+
formatReturnValue = formatReturnValue,
|
|
7470
|
+
recoverPayloadRequireError = recoverPayloadRequireError,
|
|
7471
|
+
remapPayloadLines = remapPayloadLines,
|
|
7181
7472
|
}
|
|
7182
7473
|
]]></string>
|
|
7183
7474
|
</Properties>
|
|
7184
7475
|
</Item>
|
|
7185
|
-
<Item class="ModuleScript" referent="
|
|
7476
|
+
<Item class="ModuleScript" referent="22">
|
|
7186
7477
|
<Properties>
|
|
7187
7478
|
<string name="Name">Recording</string>
|
|
7188
7479
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -7212,7 +7503,7 @@ return {
|
|
|
7212
7503
|
]]></string>
|
|
7213
7504
|
</Properties>
|
|
7214
7505
|
</Item>
|
|
7215
|
-
<Item class="ModuleScript" referent="
|
|
7506
|
+
<Item class="ModuleScript" referent="23">
|
|
7216
7507
|
<Properties>
|
|
7217
7508
|
<string name="Name">RenderMonitor</string>
|
|
7218
7509
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -7280,12 +7571,12 @@ return {
|
|
|
7280
7571
|
]]></string>
|
|
7281
7572
|
</Properties>
|
|
7282
7573
|
</Item>
|
|
7283
|
-
<Item class="ModuleScript" referent="
|
|
7574
|
+
<Item class="ModuleScript" referent="24">
|
|
7284
7575
|
<Properties>
|
|
7285
7576
|
<string name="Name">RuntimeLogBuffer</string>
|
|
7286
7577
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
7287
7578
|
local TS = require(script.Parent.Parent.include.RuntimeLib)
|
|
7288
|
-
-- Per-
|
|
7579
|
+
-- Per-capture in-memory ring buffer for LogService.MessageOut events.
|
|
7289
7580
|
-- Powers the get_runtime_logs MCP tool. Replaces the out-of-tree LogBuffer
|
|
7290
7581
|
-- primitives + StringValue approach from chrrxs/roblox-mcp-primitives.
|
|
7291
7582
|
--
|
|
@@ -7295,12 +7586,12 @@ local TS = require(script.Parent.Parent.include.RuntimeLib)
|
|
|
7295
7586
|
-- DataModel. The buffer is bounded by a message-byte budget; oldest entries
|
|
7296
7587
|
-- drop when over budget.
|
|
7297
7588
|
--
|
|
7298
|
-
--
|
|
7589
|
+
-- Capture caveat: returned entries reflect which plugin buffer CAPTURED the
|
|
7299
7590
|
-- entry, NOT which peer's script originated the print. LogService reflects
|
|
7300
|
-
-- prints across peers in Studio Play (a server print
|
|
7301
|
-
-- server and client LogService:GetLogHistory())
|
|
7302
|
-
--
|
|
7303
|
-
--
|
|
7591
|
+
-- prints across peers in ordinary Studio Play (a server print can appear in
|
|
7592
|
+
-- server and client LogService:GetLogHistory()). The MCP-side aggregator
|
|
7593
|
+
-- exposes that as capturedBy, and only promotes it to origin peer in
|
|
7594
|
+
-- StudioTestService multiplayer sessions where peer attribution is reliable.
|
|
7304
7595
|
local _services = TS.import(script, script.Parent.Parent, "node_modules", "@rbxts", "services")
|
|
7305
7596
|
local LogService = _services.LogService
|
|
7306
7597
|
local RunService = _services.RunService
|
|
@@ -7364,7 +7655,7 @@ local function detectPeer()
|
|
|
7364
7655
|
end
|
|
7365
7656
|
return "client"
|
|
7366
7657
|
end
|
|
7367
|
-
local function query(opts,
|
|
7658
|
+
local function query(opts, capturedBy)
|
|
7368
7659
|
local _result
|
|
7369
7660
|
if opts.since ~= nil then
|
|
7370
7661
|
-- ▼ ReadonlyArray.filter ▼
|
|
@@ -7435,7 +7726,7 @@ local function query(opts, peer)
|
|
|
7435
7726
|
end
|
|
7436
7727
|
local last = if #entries > 0 then entries[#entries] else nil
|
|
7437
7728
|
local _object = {
|
|
7438
|
-
|
|
7729
|
+
capturedBy = capturedBy,
|
|
7439
7730
|
entries = result,
|
|
7440
7731
|
totalDropped = totalDropped,
|
|
7441
7732
|
}
|
|
@@ -7461,11 +7752,11 @@ return {
|
|
|
7461
7752
|
]]></string>
|
|
7462
7753
|
</Properties>
|
|
7463
7754
|
</Item>
|
|
7464
|
-
<Item class="ModuleScript" referent="
|
|
7755
|
+
<Item class="ModuleScript" referent="25">
|
|
7465
7756
|
<Properties>
|
|
7466
7757
|
<string name="Name">State</string>
|
|
7467
7758
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
7468
|
-
local CURRENT_VERSION = "2.
|
|
7759
|
+
local CURRENT_VERSION = "2.16.0"
|
|
7469
7760
|
local PLUGIN_VARIANT = "main"
|
|
7470
7761
|
local MAX_CONNECTIONS = 5
|
|
7471
7762
|
local BASE_PORT = 58741
|
|
@@ -7559,7 +7850,7 @@ return {
|
|
|
7559
7850
|
]]></string>
|
|
7560
7851
|
</Properties>
|
|
7561
7852
|
</Item>
|
|
7562
|
-
<Item class="ModuleScript" referent="
|
|
7853
|
+
<Item class="ModuleScript" referent="26">
|
|
7563
7854
|
<Properties>
|
|
7564
7855
|
<string name="Name">StopPlayMonitor</string>
|
|
7565
7856
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -7704,7 +7995,7 @@ return {
|
|
|
7704
7995
|
]]></string>
|
|
7705
7996
|
</Properties>
|
|
7706
7997
|
</Item>
|
|
7707
|
-
<Item class="ModuleScript" referent="
|
|
7998
|
+
<Item class="ModuleScript" referent="27">
|
|
7708
7999
|
<Properties>
|
|
7709
8000
|
<string name="Name">UI</string>
|
|
7710
8001
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -8475,7 +8766,7 @@ return {
|
|
|
8475
8766
|
]]></string>
|
|
8476
8767
|
</Properties>
|
|
8477
8768
|
</Item>
|
|
8478
|
-
<Item class="ModuleScript" referent="
|
|
8769
|
+
<Item class="ModuleScript" referent="28">
|
|
8479
8770
|
<Properties>
|
|
8480
8771
|
<string name="Name">Utils</string>
|
|
8481
8772
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -9005,11 +9296,11 @@ return {
|
|
|
9005
9296
|
</Properties>
|
|
9006
9297
|
</Item>
|
|
9007
9298
|
</Item>
|
|
9008
|
-
<Item class="Folder" referent="
|
|
9299
|
+
<Item class="Folder" referent="32">
|
|
9009
9300
|
<Properties>
|
|
9010
9301
|
<string name="Name">include</string>
|
|
9011
9302
|
</Properties>
|
|
9012
|
-
<Item class="ModuleScript" referent="
|
|
9303
|
+
<Item class="ModuleScript" referent="29">
|
|
9013
9304
|
<Properties>
|
|
9014
9305
|
<string name="Name">Promise</string>
|
|
9015
9306
|
<string name="Source"><![CDATA[--[[
|
|
@@ -11083,7 +11374,7 @@ return Promise
|
|
|
11083
11374
|
]]></string>
|
|
11084
11375
|
</Properties>
|
|
11085
11376
|
</Item>
|
|
11086
|
-
<Item class="ModuleScript" referent="
|
|
11377
|
+
<Item class="ModuleScript" referent="30">
|
|
11087
11378
|
<Properties>
|
|
11088
11379
|
<string name="Name">RuntimeLib</string>
|
|
11089
11380
|
<string name="Source"><![CDATA[local Promise = require(script.Parent.Promise)
|
|
@@ -11350,15 +11641,15 @@ return TS
|
|
|
11350
11641
|
</Properties>
|
|
11351
11642
|
</Item>
|
|
11352
11643
|
</Item>
|
|
11353
|
-
<Item class="Folder" referent="
|
|
11644
|
+
<Item class="Folder" referent="33">
|
|
11354
11645
|
<Properties>
|
|
11355
11646
|
<string name="Name">node_modules</string>
|
|
11356
11647
|
</Properties>
|
|
11357
|
-
<Item class="Folder" referent="
|
|
11648
|
+
<Item class="Folder" referent="34">
|
|
11358
11649
|
<Properties>
|
|
11359
11650
|
<string name="Name">@rbxts</string>
|
|
11360
11651
|
</Properties>
|
|
11361
|
-
<Item class="ModuleScript" referent="
|
|
11652
|
+
<Item class="ModuleScript" referent="31">
|
|
11362
11653
|
<Properties>
|
|
11363
11654
|
<string name="Name">services</string>
|
|
11364
11655
|
<string name="Source"><![CDATA[return setmetatable({}, {
|