@chrrxs/robloxstudio-mcp 2.23.1 → 3.0.1

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 (50) hide show
  1. package/dist/index.js +1688 -4547
  2. package/package.json +7 -5
  3. package/studio-plugin/MCPPlugin.rbxmx +489 -1965
  4. package/studio-plugin/.Carbon.rbxm.lock +0 -0
  5. package/studio-plugin/Carbon.rbxm +0 -0
  6. package/studio-plugin/INSTALLATION.md +0 -170
  7. package/studio-plugin/MCPInspectorPlugin.rbxmx +0 -171527
  8. package/studio-plugin/default.project.json +0 -19
  9. package/studio-plugin/dev.project.json +0 -23
  10. package/studio-plugin/include/LibMP.lua +0 -156378
  11. package/studio-plugin/inspector-icon.png +0 -0
  12. package/studio-plugin/package-lock.json +0 -706
  13. package/studio-plugin/package.json +0 -19
  14. package/studio-plugin/plugin.json +0 -10
  15. package/studio-plugin/src/modules/AssetSanitizationPolicy.ts +0 -127
  16. package/studio-plugin/src/modules/ClientBroker.ts +0 -450
  17. package/studio-plugin/src/modules/Communication.ts +0 -632
  18. package/studio-plugin/src/modules/EvalBridges.ts +0 -255
  19. package/studio-plugin/src/modules/HttpDiagnostics.ts +0 -50
  20. package/studio-plugin/src/modules/LuauExec.ts +0 -403
  21. package/studio-plugin/src/modules/Recording.ts +0 -28
  22. package/studio-plugin/src/modules/RenderMonitor.ts +0 -60
  23. package/studio-plugin/src/modules/RuntimeLogBuffer.ts +0 -210
  24. package/studio-plugin/src/modules/ServerUrlSettings.ts +0 -117
  25. package/studio-plugin/src/modules/State.ts +0 -39
  26. package/studio-plugin/src/modules/StopPlayMonitor.ts +0 -267
  27. package/studio-plugin/src/modules/UI.ts +0 -597
  28. package/studio-plugin/src/modules/Utils.ts +0 -469
  29. package/studio-plugin/src/modules/handlers/AssetHandlers.ts +0 -391
  30. package/studio-plugin/src/modules/handlers/BreakpointHandlers.ts +0 -460
  31. package/studio-plugin/src/modules/handlers/BuildHandlers.ts +0 -481
  32. package/studio-plugin/src/modules/handlers/CaptureHandlers.ts +0 -170
  33. package/studio-plugin/src/modules/handlers/EvalRuntimeHandlers.ts +0 -149
  34. package/studio-plugin/src/modules/handlers/GenerateModelHandlers.ts +0 -168
  35. package/studio-plugin/src/modules/handlers/InputHandlers.ts +0 -163
  36. package/studio-plugin/src/modules/handlers/InstanceHandlers.ts +0 -380
  37. package/studio-plugin/src/modules/handlers/LogHandlers.ts +0 -14
  38. package/studio-plugin/src/modules/handlers/MemoryHandlers.ts +0 -44
  39. package/studio-plugin/src/modules/handlers/MetadataHandlers.ts +0 -354
  40. package/studio-plugin/src/modules/handlers/MicroProfilerHandlers.ts +0 -1263
  41. package/studio-plugin/src/modules/handlers/PropertyHandlers.ts +0 -191
  42. package/studio-plugin/src/modules/handlers/QueryHandlers.ts +0 -874
  43. package/studio-plugin/src/modules/handlers/SceneAnalysisHandlers.ts +0 -216
  44. package/studio-plugin/src/modules/handlers/ScriptHandlers.ts +0 -530
  45. package/studio-plugin/src/modules/handlers/ScriptProfilerHandlers.ts +0 -386
  46. package/studio-plugin/src/modules/handlers/SerializationHandlers.ts +0 -172
  47. package/studio-plugin/src/modules/handlers/TestHandlers.ts +0 -350
  48. package/studio-plugin/src/server/index.server.ts +0 -135
  49. package/studio-plugin/src/types/index.d.ts +0 -57
  50. package/studio-plugin/tsconfig.json +0 -20
@@ -1,354 +0,0 @@
1
- import { CollectionService } from "@rbxts/services";
2
- import Utils from "../Utils";
3
- import Recording from "../Recording";
4
- import LuauExec from "../LuauExec";
5
-
6
- const ChangeHistoryService = game.GetService("ChangeHistoryService");
7
- const Selection = game.GetService("Selection");
8
-
9
- const { getInstancePath, getInstanceByPath } = Utils;
10
- const { beginRecording, finishRecording } = Recording;
11
-
12
- function serializeValue(value: unknown): unknown {
13
- const vType = typeOf(value);
14
- if (vType === "Vector3") {
15
- const v = value as Vector3;
16
- return { X: v.X, Y: v.Y, Z: v.Z, _type: "Vector3" };
17
- } else if (vType === "Color3") {
18
- const v = value as Color3;
19
- return { R: v.R, G: v.G, B: v.B, _type: "Color3" };
20
- } else if (vType === "CFrame") {
21
- const v = value as CFrame;
22
- return { Position: { X: v.Position.X, Y: v.Position.Y, Z: v.Position.Z }, _type: "CFrame" };
23
- } else if (vType === "UDim2") {
24
- const v = value as UDim2;
25
- return {
26
- X: { Scale: v.X.Scale, Offset: v.X.Offset },
27
- Y: { Scale: v.Y.Scale, Offset: v.Y.Offset },
28
- _type: "UDim2",
29
- };
30
- } else if (vType === "BrickColor") {
31
- const v = value as BrickColor;
32
- return { Name: v.Name, _type: "BrickColor" };
33
- }
34
- return value;
35
- }
36
-
37
- function deserializeValue(attributeValue: unknown, valueType?: string): unknown {
38
- if (!typeIs(attributeValue, "table")) return attributeValue;
39
-
40
- const tbl = attributeValue as Record<string, unknown>;
41
- const t = (tbl._type as string) ?? valueType;
42
-
43
- if (t === "Vector3") {
44
- return new Vector3((tbl.X as number) ?? 0, (tbl.Y as number) ?? 0, (tbl.Z as number) ?? 0);
45
- } else if (t === "Color3") {
46
- return new Color3((tbl.R as number) ?? 0, (tbl.G as number) ?? 0, (tbl.B as number) ?? 0);
47
- } else if (t === "UDim2") {
48
- const x = tbl.X as Record<string, number> | undefined;
49
- const y = tbl.Y as Record<string, number> | undefined;
50
- return new UDim2(x?.Scale ?? 0, x?.Offset ?? 0, y?.Scale ?? 0, y?.Offset ?? 0);
51
- } else if (t === "BrickColor") {
52
- return new BrickColor(((tbl.Name as string) ?? "Medium stone grey") as unknown as number);
53
- }
54
- return attributeValue;
55
- }
56
-
57
- function setAttribute(requestData: Record<string, unknown>) {
58
- const instancePath = requestData.instancePath as string;
59
- const attributeName = requestData.attributeName as string;
60
- const attributeValue = requestData.attributeValue;
61
- const valueType = requestData.valueType as string | undefined;
62
-
63
- if (!instancePath || !attributeName) {
64
- return { error: "Instance path and attribute name are required" };
65
- }
66
-
67
- const instance = getInstanceByPath(instancePath);
68
- if (!instance) return { error: `Instance not found: ${instancePath}` };
69
- const recordingId = beginRecording(`Set attribute ${attributeName} on ${instance.Name}`);
70
-
71
- const [success, result] = pcall(() => {
72
- const value = deserializeValue(attributeValue, valueType);
73
- instance.SetAttribute(attributeName, value as AttributeValue);
74
-
75
- return {
76
- success: true, instancePath, attributeName,
77
- value: attributeValue, message: "Attribute set successfully",
78
- };
79
- });
80
-
81
- if (success) {
82
- finishRecording(recordingId, true);
83
- return result;
84
- }
85
- finishRecording(recordingId, false);
86
- return { error: `Failed to set attribute: ${result}` };
87
- }
88
-
89
- function getAttributes(requestData: Record<string, unknown>) {
90
- const instancePath = requestData.instancePath as string;
91
- if (!instancePath) return { error: "Instance path is required" };
92
-
93
- const instance = getInstanceByPath(instancePath);
94
- if (!instance) return { error: `Instance not found: ${instancePath}` };
95
-
96
- const [success, result] = pcall(() => {
97
- const attributes = instance.GetAttributes();
98
- const serializedAttributes: Record<string, { value: unknown; type: string }> = {};
99
- let count = 0;
100
-
101
- for (const [name, value] of pairs(attributes)) {
102
- serializedAttributes[name as string] = {
103
- value: serializeValue(value),
104
- type: typeOf(value),
105
- };
106
- count++;
107
- }
108
-
109
- return { instancePath, attributes: serializedAttributes, count };
110
- });
111
-
112
- if (success) return result;
113
- return { error: `Failed to get attributes: ${result}` };
114
- }
115
-
116
- function deleteAttribute(requestData: Record<string, unknown>) {
117
- const instancePath = requestData.instancePath as string;
118
- const attributeName = requestData.attributeName as string;
119
-
120
- if (!instancePath || !attributeName) {
121
- return { error: "Instance path and attribute name are required" };
122
- }
123
-
124
- const instance = getInstanceByPath(instancePath);
125
- if (!instance) return { error: `Instance not found: ${instancePath}` };
126
- const recordingId = beginRecording(`Delete attribute ${attributeName} from ${instance.Name}`);
127
-
128
- const [success, result] = pcall(() => {
129
- const existed = instance.GetAttribute(attributeName) !== undefined;
130
- instance.SetAttribute(attributeName, undefined);
131
-
132
- return {
133
- success: true, instancePath, attributeName, existed,
134
- message: existed ? "Attribute deleted successfully" : "Attribute did not exist",
135
- };
136
- });
137
-
138
- if (success) {
139
- finishRecording(recordingId, true);
140
- return result;
141
- }
142
- finishRecording(recordingId, false);
143
- return { error: `Failed to delete attribute: ${result}` };
144
- }
145
-
146
- function getTags(requestData: Record<string, unknown>) {
147
- const instancePath = requestData.instancePath as string;
148
- if (!instancePath) return { error: "Instance path is required" };
149
-
150
- const instance = getInstanceByPath(instancePath);
151
- if (!instance) return { error: `Instance not found: ${instancePath}` };
152
-
153
- const [success, result] = pcall(() => {
154
- const tags = CollectionService.GetTags(instance);
155
- return { instancePath, tags, count: tags.size() };
156
- });
157
-
158
- if (success) return result;
159
- return { error: `Failed to get tags: ${result}` };
160
- }
161
-
162
- function addTag(requestData: Record<string, unknown>) {
163
- const instancePath = requestData.instancePath as string;
164
- const tagName = requestData.tagName as string;
165
-
166
- if (!instancePath || !tagName) {
167
- return { error: "Instance path and tag name are required" };
168
- }
169
-
170
- const instance = getInstanceByPath(instancePath);
171
- if (!instance) return { error: `Instance not found: ${instancePath}` };
172
- const recordingId = beginRecording(`Add tag ${tagName} to ${instance.Name}`);
173
-
174
- const [success, result] = pcall(() => {
175
- const alreadyHad = CollectionService.HasTag(instance, tagName);
176
- CollectionService.AddTag(instance, tagName);
177
-
178
- return {
179
- success: true, instancePath, tagName, alreadyHad,
180
- message: alreadyHad ? "Instance already had this tag" : "Tag added successfully",
181
- };
182
- });
183
-
184
- if (success) {
185
- finishRecording(recordingId, true);
186
- return result;
187
- }
188
- finishRecording(recordingId, false);
189
- return { error: `Failed to add tag: ${result}` };
190
- }
191
-
192
- function removeTag(requestData: Record<string, unknown>) {
193
- const instancePath = requestData.instancePath as string;
194
- const tagName = requestData.tagName as string;
195
-
196
- if (!instancePath || !tagName) {
197
- return { error: "Instance path and tag name are required" };
198
- }
199
-
200
- const instance = getInstanceByPath(instancePath);
201
- if (!instance) return { error: `Instance not found: ${instancePath}` };
202
- const recordingId = beginRecording(`Remove tag ${tagName} from ${instance.Name}`);
203
-
204
- const [success, result] = pcall(() => {
205
- const hadTag = CollectionService.HasTag(instance, tagName);
206
- CollectionService.RemoveTag(instance, tagName);
207
-
208
- return {
209
- success: true, instancePath, tagName, hadTag,
210
- message: hadTag ? "Tag removed successfully" : "Instance did not have this tag",
211
- };
212
- });
213
-
214
- if (success) {
215
- finishRecording(recordingId, true);
216
- return result;
217
- }
218
- finishRecording(recordingId, false);
219
- return { error: `Failed to remove tag: ${result}` };
220
- }
221
-
222
- function getTagged(requestData: Record<string, unknown>) {
223
- const tagName = requestData.tagName as string;
224
- if (!tagName) return { error: "Tag name is required" };
225
-
226
- const [success, result] = pcall(() => {
227
- const taggedInstances = CollectionService.GetTagged(tagName);
228
- const instances = taggedInstances.map((instance) => ({
229
- name: instance.Name,
230
- className: instance.ClassName,
231
- path: getInstancePath(instance),
232
- }));
233
-
234
- return { tagName, instances, count: instances.size() };
235
- });
236
-
237
- if (success) return result;
238
- return { error: `Failed to get tagged instances: ${result}` };
239
- }
240
-
241
- function getSelection(_requestData: Record<string, unknown>) {
242
- const selection = Selection.Get();
243
-
244
- if (selection.size() === 0) {
245
- return { success: true, selection: [], count: 0, message: "No objects selected" };
246
- }
247
-
248
- const selectedObjects = selection.map((instance: Instance) => ({
249
- name: instance.Name,
250
- className: instance.ClassName,
251
- path: getInstancePath(instance),
252
- parent: instance.Parent ? getInstancePath(instance.Parent) : undefined,
253
- }));
254
-
255
- return {
256
- success: true,
257
- selection: selectedObjects,
258
- count: selection.size(),
259
- message: `${selection.size()} object(s) selected`,
260
- };
261
- }
262
-
263
- function executeLuau(requestData: Record<string, unknown>) {
264
- const code = requestData.code as string;
265
- if (!code || code === "") return { error: "Code is required" };
266
- // All wrapping, print/warn capture, loadstring fallback, JSON-encoding
267
- // of table returns, and parse-error recovery live in LuauExec so the
268
- // edit/server (this handler) and the play-client (ClientBroker) take
269
- // the same code path and produce identical output shapes.
270
- return LuauExec.execute(code);
271
- }
272
-
273
- function undo(_requestData: Record<string, unknown>) {
274
- const [success, result] = pcall(() => {
275
- ChangeHistoryService.Undo();
276
- return {
277
- success: true,
278
- message: "Undo executed successfully",
279
- };
280
- });
281
-
282
- if (success) return result;
283
- return { error: `Failed to undo: ${result}` };
284
- }
285
-
286
- function redo(_requestData: Record<string, unknown>) {
287
- const [success, result] = pcall(() => {
288
- ChangeHistoryService.Redo();
289
- return {
290
- success: true,
291
- message: "Redo executed successfully",
292
- };
293
- });
294
-
295
- if (success) return result;
296
- return { error: `Failed to redo: ${result}` };
297
- }
298
-
299
- function bulkSetAttributes(requestData: Record<string, unknown>) {
300
- const instancePath = requestData.instancePath as string;
301
- const attributes = requestData.attributes as Record<string, unknown>;
302
-
303
- if (!instancePath || !attributes) {
304
- return { error: "Instance path and attributes are required" };
305
- }
306
-
307
- const instance = getInstanceByPath(instancePath);
308
- if (!instance) return { error: `Instance not found: ${instancePath}` };
309
-
310
- const recordingId = beginRecording(`Bulk set attributes on ${instance.Name}`);
311
-
312
- const results: Record<string, unknown>[] = [];
313
- let successCount = 0;
314
- let failureCount = 0;
315
-
316
- for (const [name, rawValue] of pairs(attributes)) {
317
- const attrName = name as string;
318
- const [ok, err] = pcall(() => {
319
- const value = deserializeValue(rawValue);
320
- instance.SetAttribute(attrName, value as AttributeValue);
321
- });
322
-
323
- if (ok) {
324
- successCount++;
325
- results.push({ attributeName: attrName, success: true });
326
- } else {
327
- failureCount++;
328
- results.push({ attributeName: attrName, success: false, error: tostring(err) });
329
- }
330
- }
331
-
332
- finishRecording(recordingId, successCount > 0);
333
-
334
- return {
335
- instancePath,
336
- results,
337
- summary: { total: successCount + failureCount, succeeded: successCount, failed: failureCount },
338
- };
339
- }
340
-
341
- export = {
342
- setAttribute,
343
- getAttributes,
344
- deleteAttribute,
345
- getTags,
346
- addTag,
347
- removeTag,
348
- getTagged,
349
- getSelection,
350
- executeLuau,
351
- undo,
352
- redo,
353
- bulkSetAttributes,
354
- };